home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft_Programmers_Library.7z / MPL / masm / qapgrmg.txt < prev   
Encoding:
Text File  |  2013-11-08  |  829.6 KB  |  20,649 lines

  1.  Microsoft(R) QuickAssembler Programmer's Guide Version 2.01
  2.  
  3.  
  4.  ════════════════════════════════════════════════════════════════════════════
  5.  
  6.  
  7.  Microsoft(R) QuickAssembler Programmer's Guide Version 2.01
  8.  
  9.  
  10.  ════════════════════════════════════════════════════════════════════════════
  11.  
  12.  
  13.    Information in this document is subject to change without notice and does
  14.    not represent a commitment on the part of Microsoft Corporation. The
  15.    software described in this document is furnished under a license agreement
  16.    or nondisclosure agreement. The software may be used or copied only in
  17.    accordance with the terms of the agreement. It is against the law to copy
  18.    the software on any medium except as specifically allowed in the license
  19.    or nondisclosure agreement. No part of this manual may be reproduced or
  20.    transmitted in any form or by any means, electronic or mechanical,
  21.    including photocopying and recording, for any purpose without the express
  22.    written permission of Microsoft.
  23.  
  24.    (C)Copyright Microsoft Corporation, 1989. All rights reserved.
  25.    Simultaneously published in the U.S. and Canada.
  26.  
  27.    Printed and bound in the United States of America.
  28.  
  29.    Microsoft, MS, MS-DOS, GW-BASIC, QuickC, and XENIX are registered
  30.    trademarks of Microsoft Corporation.
  31.  
  32.    IBM is a registered trademark of International Business Machines
  33.    Corporation.
  34.  
  35.    Intel is a registered trademark of Intel Corporation.
  36.  
  37.    Document No. LN0114-201-R00-0689
  38.    Part No. 06792
  39.    10  9  8  7  6  5  4  3  2  1
  40.  
  41.  
  42.  
  43.  
  44.  
  45.  ────────────────────────────────────────────────────────────────────────────
  46.  Table of Contents
  47.  
  48.  Introduction
  49.  
  50.  Chapter 1  The QuickAssembler Interface
  51.          1.1  Creating the Program
  52.          1.2  Building and Running a Program
  53.          1.3  Assembling from the Command Line
  54.          1.4  Choosing C or Assembler Defaults
  55.          1.5  Using the Quick Advisor (Help)
  56.          1.6  Debugging Assembly Code
  57.               1.6.1  Debugging .COM Files
  58.               1.6.2  Specifying Expressions
  59.               1.6.3  Tracing Execution
  60.               1.6.4  Modifying Registers and Flags
  61.          1.7  Viewing a Listing File
  62.  
  63.  Chapter 2  Introducing 8086 Assembly Language
  64.          2.1  Programming the 8086 Family
  65.          2.2  Instructions, Directives, and Operands
  66.               2.2.1  The Name Field
  67.               2.2.2  The Operation Field
  68.               2.2.3  The Operand Field
  69.               2.2.4  The Comment Field
  70.               2.2.5  Entering Numbers in Different Bases
  71.               2.2.6  Line-Continuation Character
  72.          2.3  8086-Family Instructions
  73.               2.3.1  Data-Manipulation Instructions
  74.                      2.3.1.1  The MOV Instruction
  75.                      2.3.1.2  The ADD Instruction
  76.                      2.3.1.3  The SUB Instruction
  77.                      2.3.1.4  The INC and DEC Instructions
  78.                      2.3.1.5  The AND Instruction
  79.                      2.3.1.6  The MUL Instruction
  80.               2.3.2  Control-Flow Instructions
  81.                      2.3.2.1  The JMP Instruction
  82.                      2.3.2.2  The CMP Instruction
  83.                      2.3.2.3  The Conditional Jump Instructions
  84.          2.4  Declaring Simple Data Objects
  85.          2.5  8086-Family Registers
  86.               2.5.1  The General-Purpose Registers
  87.                      2.5.1.1  The AX Register
  88.                      2.5.1.2  The BX Register
  89.                      2.5.1.3  The CX Register
  90.                      2.5.1.4  The DX Register
  91.               2.5.2  The Index Registers
  92.               2.5.3  The Pointer Registers
  93.                      2.5.3.1  The BP Register
  94.                      2.5.3.2  The SP Register
  95.                      2.5.3.3  The IP Register
  96.               2.5.4  The Flags Register
  97.          2.6  Addressing Modes
  98.               2.6.1  Immediate Operands
  99.               2.6.2  Register Operands
  100.               2.6.3  Direct Memory Operands
  101.               2.6.4  Indirect Memory Operands
  102.          2.7  Segmented Addressing and Segment Registers
  103.  
  104.  Chapter 3  Writing Assembly Modules for C Programs
  105.          3.1  A Skeleton for Procedure Modules
  106.               3.1.1  The .MODEL Directive
  107.               3.1.2  The .CODE Directive
  108.               3.1.3  The PROC Directive
  109.               3.1.4  The ENDP and END Statements
  110.          3.2  Instructions Used in This Chapter
  111.          3.3  Decimal Conversion Example
  112.          3.4  Decimal Conversion with Far Data Pointers
  113.               3.4.1  Writing a Model-Independent Procedure
  114.               3.4.2  Accessing Far Data through ES
  115.          3.5  Hexadecimal Conversion Example
  116.  
  117.  Chapter 4  Writing Stand-Alone Assembly Programs
  118.          4.1  A Skeleton for Stand-Alone Programs
  119.               4.1.1  The .MODEL Directive
  120.               4.1.2  The .STACK, .CODE, and .DATA Directives
  121.               4.1.3  The .STARTUP Directive
  122.          4.2  Instructions Used in This Chapter
  123.          4.3  A Program That Says Hello
  124.          4.4  Inside the Stack Segment
  125.          4.5  Inside the Data Segment
  126.          4.6  Inside the Code Segment
  127.          4.7  Making the Program Repeat Itself
  128.          4.8  Creating .COM Files
  129.          4.9  Creating .COM Files with Full Segment Definitions
  130.  
  131.  Chapter 5  Defining Segment Structure
  132.          5.1  Simplified Segment Directives
  133.               5.1.1  Understanding Memory Models
  134.               5.1.2  Specifying DOS Segment Order
  135.               5.1.3  Defining Basic Attributes of the Module
  136.               5.1.4  Defining Simplified Segments
  137.                      5.1.4.1  How to Use Simplified Segments
  138.                      5.1.4.2  How Simplified Segments Are Implemented
  139.               5.1.5  Using Predefined Segment Equates
  140.               5.1.6  Simplified Segment Defaults
  141.               5.1.7  Default Segment Names
  142.          5.2  Full Segment Definitions
  143.               5.2.1  Setting the Segment-Order Method
  144.               5.2.2  Defining Full Segments
  145.                      5.2.2.1  Controlling Alignment with Align Type
  146.                      5.2.2.2  Defining Segment Combinations with Combine Type
  147.                      5.2.2.3  Controlling Segment Structure with Class Type
  148.          5.3  Defining Segment Groups
  149.          5.4  Associating Segments with Registers
  150.          5.5  Initializing Segment Registers
  151.               5.5.1  Initializing the CS and IP Registers
  152.               5.5.2  Initializing the DS Register
  153.               5.5.3  Initializing the SS and SP Registers
  154.               5.5.4  Initializing the ES Register
  155.          5.6  Nesting Segments
  156.  
  157.  Chapter 6  Defining Constants, Labels, and Variables
  158.          6.1  Constants
  159.               6.1.1  Integer Constants
  160.                      6.1.1.1  Specifying Integers with Radix Specifiers
  161.                      6.1.1.2  Setting the Default Radix
  162.               6.1.2  Packed Binary Coded Decimal Constants
  163.               6.1.3  Real-Number Constants
  164.               6.1.4  String Constants
  165.               6.1.5  Determining Floating-Point Format
  166.          6.2  Assigning Names to Symbols
  167.          6.3  Using Type Specifiers
  168.          6.4  Defining Code Labels
  169.               6.4.1  Near-Code Labels
  170.               6.4.2  Anonymous Labels
  171.               6.4.3  Procedure Labels
  172.               6.4.4  Code Labels Defined with the LABEL Directive
  173.          6.5  Defining and Initializing Data
  174.               6.5.1  Variables
  175.                      6.5.1.1  Integer Variables
  176.                      6.5.1.2  Binary Coded Decimal Variables
  177.                      6.5.1.3  String Variables
  178.                      6.5.1.4  Real-Number Variables
  179.               6.5.2  Arrays and Buffers
  180.               6.5.3  Labeling Variables
  181.               6.5.4  Pointer Variables
  182.          6.6  Setting the Location Counter
  183.          6.7  Aligning Data
  184.  
  185.  Chapter 7  Using Structures and Records
  186.          7.1  Structures
  187.               7.1.1  Declaring Structure Types
  188.               7.1.2  Defining Structure Variables
  189.               7.1.3  Using Structure Operands
  190.          7.2  Records
  191.               7.2.1  Declaring Record Types
  192.               7.2.2  Defining Record Variables
  193.               7.2.3  Using Record Operands and Record Variables
  194.               7.2.4  Record Operators
  195.                      7.2.4.1  The MASK Operator
  196.                      7.2.4.2  The WIDTH Operator
  197.               7.2.5  Using Record-Field Operands
  198.  
  199.  Chapter 8  Creating Programs from Multiple Modules
  200.          8.1  Declaring Symbols Public
  201.          8.2  Declaring Symbols External
  202.          8.3  Using Multiple Modules
  203.          8.4  Declaring Symbols Communal
  204.          8.5  Specifying Library Files
  205.  
  206.  Chapter 9  Using Operands and Expressions
  207.          9.1  Using Operands with Directives
  208.          9.2  Using Operators
  209.               9.2.1  Calculation Operators
  210.                      9.2.1.1  Arithmetic Operators
  211.                      9.2.1.2  Structure-Field-Name Operator
  212.                      9.2.1.3  Index Operator
  213.                      9.2.1.4  Shift Operators
  214.                      9.2.1.5  Bitwise Logical Operators
  215.               9.2.2  Relational Operators
  216.               9.2.3  Segment-Override Operator
  217.               9.2.4  Type Operators
  218.                      9.2.4.1  PTR Operator
  219.                      9.2.4.2  SHORT Operator
  220.                      9.2.4.3  THIS Operator
  221.                      9.2.4.4  HIGH and LOW Operators
  222.                      9.2.4.5  SEG Operator
  223.                      9.2.4.6  OFFSET Operator
  224.                      9.2.4.7  .TYPE Operator
  225.                      9.2.4.8  TYPE Operator
  226.                      9.2.4.9  LENGTH Operator
  227.                      9.2.4.10  SIZE Operator
  228.               9.2.5  Operator Precedence
  229.          9.3  Using the Location Counter
  230.          9.4  Using Forward References
  231.               9.4.1  Forward References to Labels
  232.               9.4.2  Forward References to Variables
  233.          9.5  Strong Typing for Memory Operands
  234.  
  235.  Chapter 10  Assembling Conditionally
  236.          10.1  Using Conditional-Assembly Directives
  237.                10.1.1  Testing Expressions with IF and IFE Directives
  238.                10.1.2  Testing the Pass with IF1 and IF2 Directives
  239.                10.1.3  Testing Symbol Definition with IFDEF and IFNDEF Directi
  240.                10.1.4  Verifying Macro Parameters with IFB and IFNB Directives
  241.                10.1.5  Comparing Macro Arguments with IFIDN and IFDIF Directiv
  242.                10.1.6  ELSEIF Directives
  243.          10.2  Using Conditional-Error Directives
  244.                10.2.1  Generating Unconditional Errors with .ERR, .ERR1, and .
  245.                        Directives
  246.                10.2.2  Testing Expressions with .ERRE or .ERRNZ Directives
  247.                10.2.3  Verifying Symbol Definition with .ERRDEF and .ERRNDEF
  248.                        Directives
  249.                10.2.4  Testing for Macro Parameters with .ERRB and .ERRNB
  250.                        Directives
  251.                10.2.5  Comparing Macro Arguments with .ERRIDN and .ERRDIF
  252.                        Directives
  253.  
  254.  Chapter 11  Using Equates, Macros, and Repeat Blocks
  255.          11.1  Using Equates
  256.                11.1.1  Redefinable Numeric Equates
  257.                11.1.2  Nonredefinable Numeric Equates
  258.                11.1.3  String Equates
  259.                11.1.4  Predefined Equates
  260.          11.2  Using Macros
  261.                11.2.1  Defining Macros
  262.                11.2.2  Calling Macros
  263.                11.2.3  Using Local Symbols
  264.                11.2.4  Exiting from a Macro
  265.          11.3  Text-Macro String Directives
  266.                11.3.1  The SUBSTR Directive
  267.                11.3.2  The CATSTR Directive
  268.                11.3.3  The SIZESTR Directive
  269.                11.3.4  The INSTR Directive
  270.                11.3.5  Using String Directives Inside Macros
  271.          11.4  Defining Repeat Blocks
  272.                11.4.1  The REPT Directive
  273.                11.4.2  The IRP Directive
  274.                11.4.3  The IRPC Directive
  275.          11.5  Using Macro Operators
  276.                11.5.1  Substitute Operator
  277.                11.5.2  Literal-Text Operator
  278.                11.5.3  Literal-Character Operator
  279.                11.5.4  Expression Operator
  280.                11.5.5  Macro Comments
  281.          11.6  Using Recursive, Nested, and Redefined Macros
  282.                11.6.1  Using Recursion
  283.                11.6.2  Nesting Macro Definitions
  284.                11.6.3  Nesting Macro Calls
  285.                11.6.4  Redefining Macros
  286.                11.6.5  Avoiding Inadvertent Substitutions
  287.          11.7  Managing Macros and Equates
  288.                11.7.1  Using Include Files
  289.                11.7.2  Purging Macros from Memory
  290.  
  291.  Chapter 12  Controlling Assembly Output
  292.          12.1  Sending Messages to the Standard Output Device
  293.          12.2  Controlling Page Format in Listings
  294.                12.2.1  Setting the Listing Title
  295.                12.2.2  Setting the Listing Subtitle
  296.                12.2.3  Controlling Page Breaks
  297.                12.2.4  Naming the Module
  298.          12.3  Controlling the Contents of Listings
  299.                12.3.1  Suppressing and Restoring Listing Output
  300.                12.3.2  Controlling Listing of Conditional Blocks
  301.                12.3.3  Controlling Listing of Macros
  302.  
  303.  Chapter 13  Loading, Storing, and Moving Data
  304.          13.1  Transferring Data
  305.                13.1.1  Copying Data
  306.                13.1.2  Exchanging Data
  307.                13.1.3  Looking Up Data
  308.                13.1.4  Transferring Flags
  309.          13.2  Converting between Data Sizes
  310.                13.2.1  Extending Signed Values
  311.                13.2.2  Extending Unsigned Values
  312.          13.3  Loading Pointers
  313.                13.3.1  Loading Near Pointers
  314.                13.3.2  Loading Far Pointers
  315.          13.4  Transferring Data to and from the Stack
  316.                13.4.1  Pushing and Popping
  317.                13.4.2  Using the Stack
  318.                13.4.3  Saving Flags on the Stack
  319.                13.4.4  Saving All Registers on the Stack
  320.          13.5  Transferring Data to and from Ports
  321.  
  322.  Chapter 14  Doing Arithmetic and Bit Manipulations
  323.          14.1  Adding
  324.                14.1.1  Adding Values Directly
  325.                14.1.2  Adding Values in Multiple Registers
  326.          14.2  Subtracting
  327.                14.2.1  Subtracting Values Directly
  328.                14.2.2  Subtracting with Values in Multiple Registers
  329.          14.3  Multiplying
  330.          14.4  Dividing
  331.          14.5  Calculating with Binary Coded Decimals
  332.                14.5.1  Unpacked BCD Numbers
  333.                14.5.2  Packed BCD Numbers
  334.          14.6  Doing Logical Bit Manipulations
  335.                14.6.1  AND Operations
  336.                14.6.2  OR Operations
  337.                14.6.3  XOR Operations
  338.                14.6.4  NOT Operations
  339.          14.7  Shifting and Rotating Bits
  340.                14.7.1  Multiplying and Dividing by Constants
  341.                14.7.2  Moving Bits to the Least-Significant Position
  342.                14.7.3  Adjusting Masks
  343.                14.7.4  Shifting Multiword Values
  344.  
  345.  Chapter 15  Controlling Program Flow
  346.          15.1  Jumping
  347.                15.1.1  Jumping Unconditionally
  348.                15.1.2  Jumping Conditionally
  349.                        15.1.2.1  Comparing and Jumping
  350.                        15.1.2.2  Jumping Based on Flag Status
  351.                        15.1.2.3  Testing Bits and Jumping
  352.          15.2  Looping
  353.          15.3  Using Procedures
  354.                15.3.1  Calling Procedures
  355.                15.3.2  Defining Procedures
  356.                15.3.3  Passing Arguments on the Stack
  357.                15.3.4  Declaring Parameters with the PROC Directive
  358.                15.3.5  Using Local Variables
  359.                15.3.6  Creating Locals Automatically
  360.                15.3.7  Variable Scope
  361.                15.3.8  Setting Up Stack Frames
  362.          15.4  Using Interrupts
  363.                15.4.1  Calling Interrupts
  364.                15.4.2  Defining and Redefining Interrupt Routines
  365.          15.5  Checking Memory Ranges
  366.  
  367.  Chapter 16  Processing Strings
  368.          16.1  Setting Up String Operations
  369.          16.2  Moving Strings
  370.          16.3  Searching Strings
  371.          16.4  Comparing Strings
  372.          16.5  Filling Strings
  373.          16.6  Loading Values from Strings
  374.          16.7  Transferring Strings to and from Ports
  375.  
  376.  Chapter 17  Calculating with a Math Coprocessor
  377.          17.1  Coprocessor Architecture
  378.                17.1.1  Coprocessor Data Registers
  379.                17.1.2  Coprocessor Control Registers
  380.          17.2  Emulation
  381.          17.3  Using Coprocessor Instructions
  382.                17.3.1  Using Implied Operands in the Classical-Stack Form
  383.                17.3.2  Using Memory Operands
  384.                17.3.3  Specifying Operands in the Register Form
  385.                17.3.4  Specifying Operands in the Register-Pop Form
  386.          17.4  Coordinating Memory Access
  387.          17.5  Transferring Data
  388.                17.5.1  Transferring Data to and from Registers
  389.                        17.5.1.1  Real Transfers
  390.                        17.5.1.2  Integer Transfers
  391.                        17.5.1.3  Packed BCD Transfers
  392.                17.5.2  Loading Constants
  393.                17.5.3  Transferring Control Data
  394.          17.6  Doing Arithmetic Calculations
  395.          17.7  Controlling Program Flow
  396.                17.7.1  Comparing Operands to Control Program Flow
  397.                        17.7.1.1  Compare
  398.                        17.7.1.2  Compare and Pop
  399.                17.7.2  Testing Control Flags after Other Instructions
  400.          17.8  Using Transcendental Instructions
  401.          17.9  Controlling the Coprocessor
  402.  
  403.  Chapter 18  Controlling the Processor
  404.          18.1  Controlling Timing and Alignment
  405.          18.2  Controlling the Processor
  406.          18.3  Processor Directives
  407.  
  408.  Appendix A  Mixed-Language Mechanics
  409.          A.1  Writing the Assembly Procedure
  410.               A.1.1  Setting Up the Procedure
  411.               A.1.2  Entering the Procedure
  412.               A.1.3  Allocating Local Data (Optional)
  413.               A.1.4  Preserving Register Values
  414.               A.1.5  Accessing Parameters
  415.               A.1.6  Returning a Value (Optional)
  416.               A.1.7  Exiting the Procedure
  417.          A.2  Calls from Modules Using C Conventions
  418.          A.3  Calls from Non-C Modules
  419.          A.4  Calling High-Level Languages from Assembly Language
  420.          A.5  Using Full Segment Definitions
  421.  
  422.  Appendix B  Using Assembler Options with QCL
  423.          B.1  Specifying the Segment-Order Method
  424.          B.2  Checking Code for Tiny Model
  425.          B.3  Selecting Case Sensitivity
  426.          B.4  Defining Assembler Symbols
  427.          B.5  Displaying Error Lines on the Screen
  428.          B.6  Creating Code for a Floating-Point Emulator
  429.          B.7  Creating Listing Files
  430.          B.8  Enabling One-Pass Assembly
  431.          B.9  Listing All Lines of Macro Expansions
  432.          B.10  Creating a Pass 1 Listing
  433.          B.11  Specifying an Editor-Oriented Listing
  434.          B.12  Suppressing Tables in the Listing File
  435.          B.13  Adding a Line-Number Index to the Listing
  436.          B.14  Listing False Conditionals
  437.          B.15  Controlling Display of Assembly Statistics
  438.          B.16  Setting the Warning Level
  439.  
  440.  Appendix C  Reading Assembly Listings
  441.          C.1  Reading Code in a Listing
  442.          C.2  Reading a Macro Table
  443.          C.3  Reading a Structure and Record Table
  444.          C.4  Reading a Segment and Group Table
  445.          C.5  Reading a Symbol Table
  446.          C.6  Reading Assembly Statistics
  447.          C.7  Reading a Pass 1 Listing
  448.  
  449.  Index
  450.  
  451.  
  452.  
  453.  ────────────────────────────────────────────────────────────────────────────
  454.  Introduction
  455.  
  456.  
  457.    If you're a C programmer who has been wanting to try out the full power of
  458.    assembly language, this is the product for you.
  459.  
  460.    Microsoft(R) QuickC(R) with QuickAssembler is a package you install along
  461.    with Microsoft QuickC Version 2.0 in order to create a single powerful
  462.    environment in which you can develop C, assembly, and mixed-language
  463.    programs. What's more, QuickAssembler is an integrated environment,
  464.    containing tools for editing, assembling, compiling, and linking.
  465.    Integrated tools help you achieve faster development of assembly-language
  466.    programs.
  467.  
  468.    Each MS-DOS(R) and IBM(R) PC-DOS computer is driven by one of the
  469.    processors in the 8086 family. A processor is the central motor of a
  470.    computer. It responds to its own numeric language, called "machine code."
  471.    Assembly language is very close to machine code, but it lets you use
  472.    meaningful keywords and variable names instead of difficult-to-remember
  473.    numeric codes. As a result, assembly language is convenient to use, but
  474.    gives you the ultimate in ability to control hardware and optimize code.
  475.  
  476.    To support the low-level operations of assembly language, QuickAssembler
  477.    expands the general power of the QuickC environment. Increased debugging
  478.    capabilities let you change flag settings and modify registers──including
  479.    registers of the 8087 math coprocessor. Furthermore, the Quick Advisor
  480.    (the on-line Help system) is expanded to provide help on QuickAssembler
  481.    keywords as well as DOS and ROM-BIOS services.
  482.  
  483.    A Note about Operating-System Terms
  484.  
  485.    Microsoft documentation uses the term "OS/2" to refer to the OS/2 system──
  486.    Microsoft Operating System/2 (MS(R) OS/2) and IBM OS/2. Similarly, the
  487.    term "DOS" refers to both the MS-DOS and IBM Personal Computer DOS
  488.    operating systems. The name of a specific operating system is used when it
  489.    is necessary to note features unique to that system.
  490.  
  491.  
  492.  General Features
  493.  
  494.    QuickAssembler does not replace the QuickC in-line assembler, which you
  495.    can continue to use inside .C files. The joint QuickC/QuickAssembler
  496.    environment puts both QuickAssember and the in-line assembler at your
  497.    disposal. But Microsoft QuickAssembler supports a number of features
  498.    beyond those supported by the in-line assembler:
  499.  
  500.    ■  You can write stand-alone assembly programs. These programs begin and
  501.       end with assembly code and do not include the C start-up code. Unlike
  502.       programs written from within C modules, useful stand-alone assembly
  503.       programs can be 1K (kilobyte) or even smaller.
  504.  
  505.    ■  You can use the assembler's rich set of macro-definition capabilities,
  506.       which go far beyond the macro capabilities supported by C. An
  507.       assembly-language macro can handle variable parameter lists, recursion,
  508.       and repeated operations. These macros are roughly as powerful and
  509.       flexible as procedure calls, but execute faster.
  510.  
  511.    ■  Your assembly modules can be shared by many different programs. Since
  512.       an assembly-language module is in its own file, you can write the
  513.       module once and link it to any program you want.
  514.  
  515.    ■  QuickAssembler is a full implementation of 8086 assembly language. You
  516.       can use the full set of the Microsoft Macro Assembler 5.1 directives
  517.       and operators.
  518.  
  519.    In addition, QuickAssembler provides the best set of keywords yet
  520.    available for simplifying tedious programming tasks, such as initializing
  521.    registers at the beginning of a program or determining how to access
  522.    parameters on the stack. (Part 1 of this manual focuses on the use of
  523.    these keywords.)
  524.  
  525.    QuickAssembler for QuickC is a DOS-based product, and it does not include
  526.    the following extensions to 8086 assembly language:
  527.  
  528.    ■  80386 extended registers and special instructions
  529.  
  530.    ■  80387 extended instructions
  531.  
  532.    ■  OS/2 protected-mode operation
  533.  
  534.    QuickAssembler does support the 80286 extended instruction set, as well as
  535.    the 8087 and 80287 coprocessors. The 80386 processor can run all
  536.    QuickAssembler programs; the only limitation is that QuickAssembler does
  537.    not support extended capabilities of the 80386.
  538.  
  539.    The Microsoft Macro Assembler supports 80386 extended features and
  540.    development of protected-mode applications.
  541.  
  542.  
  543.  System Requirements
  544.  
  545.    In addition to a computer with one of the 8086-family processors, you must
  546.    have Version 2.1 or later of the MS-DOS or IBM PC-DOS operating system.
  547.    You can also run QuickAssembler in the 3.x compatibility box of OS/2
  548.    systems. Your computer system must have approximately 512K of memory. A
  549.    hard-disk setup is strongly recommended.
  550.  
  551.    To enable the use of QuickAssembler, you should first choose Full Menus
  552.    from the Options menu.
  553.  
  554.    ──────────────────────────────────────────────────────────────────────────
  555.    NOTE  The 8086 family is a set of processors that all support the same
  556.    basic instruction set. This family includes the 8088, 8086, 80188, 80186,
  557.    80286, and 80386 chips. All of these processors support the entire
  558.    instruction set of the 8086 itself; some support additional instructions.
  559.    Rather than list the entire set of chips, this manual often discusses the
  560.    core instruction set by referring only to the 8086.
  561.    ──────────────────────────────────────────────────────────────────────────
  562.  
  563.  
  564.  Installing QuickAssembler
  565.  
  566.    If you purchased QuickC and QuickAssembler together, the installation
  567.    procedure described in Up and Running automatically installs both
  568.    products. A few of the questions shown in that booklet are reworded in the
  569.    install program to make more sense for the joint QuickC/QuickAssembler
  570.    installation.
  571.  
  572.    If you purchased QuickAssembler separately, run the installation program
  573.    on the QuickAssembler distribution disks. The first screen asks you the
  574.    following questions:
  575.  
  576.    Source of assembler files [A:]:
  577.    Installing on a hard disk drive [Y]:
  578.    Copy QuickAssembler documentation files [Y]:
  579.    Copy sample Assembler programs [N]:
  580.  
  581.    Do you want to change any of the above options? [N]
  582.  
  583.    As with the QuickC installation program, the default responses are
  584.    indicated in brackets ([]). Each of these questions is accompanied by an
  585.    explanation at the bottom of the screen. To accept a default response,
  586.    press ENTER. If you enter an incorrect response, just answer no (N) to the
  587.    last question.
  588.  
  589.    The second screen asks you the following questions:
  590.  
  591.    Directory for QuickC executable files [C:\QC2\BIN]:
  592.    Directory for Sample files [C:\QC2\SAMPLES]:
  593.  
  594.    Do you want to change any of the above options? [N]
  595.  
  596.    The QuickAssembler installation program replaces some of the existing
  597.    QuickC files. QuickAssembler must be installed in the directory that
  598.    currently contains QC.EXE. Make sure you enter the location of your
  599.    current QuickC executable files. If you're not sure, press CTRL+C to stop
  600.    the installation and examine your setup.
  601.  
  602.  
  603.  Getting Information about Assembly Language
  604.  
  605.    The combined paper and on-line documentation with QuickAssembler gives you
  606.    a complete reference to the language. This manual provides three basic
  607.    kinds of information:
  608.  
  609.    ■  Part 1, "Introducing QuickAssembler," provides a basic introduction to
  610.       programming in assembly language. Chapter 1 describes how the
  611.       interface changes when you install QuickAssembler. Chapter 2 gives a
  612.       general background to 8086 architecture and assembly-language concepts.
  613.       Chapters 3 and 4 demonstrate how to use special QuickAssembler
  614.       keywords to simplify programming. Even if you have used assembly
  615.       language before, you should take a look at these chapters.
  616.  
  617.    ■  Parts 2 ("Using Directives") and 3 ("Using Instructions") give a
  618.       reference to the use of directives and instructions. This material is
  619.       much less tutorial than Part 1, but it does illustrate the use of each
  620.       directive and instruction in context.
  621.  
  622.    ■  The appendixes explain low-level mixed-language techniques, the use of
  623.       assembly options with the QCL driver, and how to read listing files.
  624.  
  625.    This manual does not teach systems programming or advanced programming
  626.    techniques. Even with the tutorial material provided in this manual, you
  627.    may want to purchase other books on assembly language, such as the ones
  628.    listed in the next section.
  629.  
  630.    In addition, this manual assumes you understand certain basic concepts of
  631.    programming, such as modules, variables, and pointers. If you need more
  632.    background in one of these topics, you should first read the appropriate
  633.    sections in C For Yourself. Part 1 of this manual often explains concepts
  634.    by comparing a language feature to C.
  635.  
  636.    The Quick Advisor (the on-line Help system) is an integral part of the
  637.    overall documentation. As explained in Section 1.5, "Using the Quick
  638.    Advisor (Help)," QuickAssembler provides help on all keywords──in
  639.    particular, you get instant reference information on each instruction,
  640.    including timing, encoding, and flag settings. The Help Contents and Index
  641.    screens also provide information on each DOS service.
  642.  
  643.  
  644.  Books on Assembly Language
  645.  
  646.    The following books may be useful in learning to program in assembly
  647.    language:
  648.  
  649.    Duncan, Ray. Advanced MS-DOS. Redmond, WA: Microsoft Corporation, 1986.
  650.  
  651.      An intermediate book on writing C and assembly-language programs that
  652.      interact with MS-DOS (includes DOS and BIOS function descriptions)
  653.  
  654.    Jourdain, Robert. Programmer's Problem Solver for the IBM PC, XT and AT.
  655.      New York: Brady Communications Company, Inc., 1986.
  656.  
  657.      Reference of routines and techniques for interacting with hardware
  658.      devices through DOS, BIOS, and ports (high-level routines in BASIC and
  659.      low- or medium-level routines in assembler)
  660.  
  661.    Lafore, Robert. Assembly Language Primer for the IBM PC & XT. New York:
  662.      Plume/Waite, 1984.
  663.  
  664.      An introduction to assembly language, including some information on DOS
  665.      function calls and IBM-type BIOS
  666.  
  667.    Metcalf, Christopher D., and Sugiyama, Marc B. COMPUTE!'s Beginner's Guide
  668.      to Machine Language on the IBM PC & PCjr. Greensboro, NC: COMPUTE!
  669.      Publications, Inc., 1985.
  670.  
  671.      Beginning discussion of assembly language, including information on the
  672.      instruction set and MS-DOS function calls
  673.  
  674.    Microsoft MS-DOS Programmer's Reference. Redmond, WA: Microsoft Press,
  675.      1986, 1987.
  676.  
  677.      Reference manual for MS-DOS
  678.  
  679.    Morgan, Christopher, and the Waite Group. Bluebook of Assembly Routines
  680.      for the IBM PC. New York: New American Library, 1984.
  681.  
  682.      Sample assembly routines that can be integrated into assembly or
  683.      high-level-language programs
  684.  
  685.    Norton, Peter. The Peter Norton Programmer's Guide to the IBM PC. Redmond,
  686.      WA: Microsoft Press, 1985.
  687.  
  688.      Information on using IBM-type BIOS and MS-DOS function calls
  689.  
  690.    Scanlon, Leo J. IBM PC Assembly Language: A Guide for Programmers. Bowie,
  691.      MD: Robert J. Brady Co., 1983.
  692.  
  693.      An introduction to assembly language, including information on DOS
  694.      function calls
  695.  
  696.    Schneider, Al. Fundamentals of IBM PC Assembly Language. Blue Ridge
  697.      Summit, PA: Tab Books Inc., 1984.
  698.  
  699.      An introduction to assembly language, including information on DOS
  700.      function calls
  701.  
  702.    These books are listed for your convenience only. Microsoft Corporation
  703.    does not endorse these books (with the exception of those published by
  704.    Microsoft) or recommend them over others on the same subjects.
  705.  
  706.  
  707.  Document Conventions
  708.  
  709.    The following document conventions are used throughout this manual:
  710.  
  711.    Example of          Description
  712.    Convention
  713.    ──────────────────────────────────────────────────────────────────────────
  714.    SAMPLE2.ASM         Uppercase letters indicate file names, segment names,
  715.                        registers, and terms used at the DOS-command level.
  716.  
  717.    .MODEL              Boldface type indicates assembly-language directives,
  718.                        instructions, type specifiers, and predefined equates,
  719.                        as well as keywords in other programming languages.
  720.  
  721.    placeholders        Italic letters indicate placeholders for information
  722.                        you must supply, such as a file name. Italics are also
  723.                        occasionally used for emphasis in the text.
  724.  
  725.    target              This font is used to indicate example programs, user
  726.                        input, and screen output.
  727.  
  728.    SHIFT               Names of keys on the keyboard appear in small capital
  729.                        letters. Notice that a plus (+) indicates a
  730.                        combination of keys. For example, CTRL+E means to hold
  731.                        down the CTRL key while pressing the E key.
  732.  
  733.    [[argument ]]       Items inside double square brackets are optional.
  734.  
  735.    {register | memory} Braces and a vertical bar indicate a choice between
  736.                        two or more items. You must choose one of the items
  737.                        unless double square brackets surround the braces.
  738.  
  739.    Repeating           Three dots following an item indicate that more items
  740.    elements...         having the same form may appear.
  741.  
  742.    Program             A column of three dots tells you that part of a
  743.    .                   program has been intentionally omitted.
  744.    .
  745.    .
  746.    Fragment
  747.  
  748.    "processor flag"    The first time a new term is defined, it is enclosed
  749.                        in quotation marks.
  750.  
  751.    Color Graphics      The first time an acronym is used, it is spelled out.
  752.    Adapter (CGA)
  753.  
  754.  
  755.  Getting Assistance or Reporting Problems
  756.  
  757.    If you need help or feel you have discovered a problem in the software,
  758.    please provide the following information to help us locate the problem:
  759.  
  760.    ■  The version of DOS you are running (use the DOS VER command)
  761.  
  762.    ■  Your system configuration (the type of machine you are using, its total
  763.       memory, and its total free memory at assembler execution time, as well
  764.       as any other information you think might be useful)
  765.  
  766.    ■  The assembly command line used (or the link command line if the problem
  767.       occurred during linking)
  768.  
  769.    ■  Any object files or libraries you linked with if the problem occurred
  770.       at link time
  771.  
  772.    If your program is very large, please try to reduce its size to the
  773.    smallest possible program that still produces the problem.
  774.  
  775.    Use the Product Assistance Request form at the back of this manual to send
  776.    this information to Microsoft.
  777.  
  778.    If you have comments or suggestions regarding any of the manuals
  779.    accompanying this product, please indicate them on the Document Feedback
  780.    card at the back of this manual.
  781.  
  782.    If you are not already a registered QuickAssembler owner, you should fill
  783.    out and return the Registration Card. This enables Microsoft to keep you
  784.    informed of updates and other information about the assembler.
  785.  
  786.  
  787.  
  788.  ────────────────────────────────────────────────────────────────────────────
  789.  PART 1:  Using Assembler Programs
  790.  
  791.  
  792.    Part 1 of the Programmer's Guide (comprising Chapters 1-4) will help
  793.    you start using assembly language quickly.
  794.  
  795.    Chapter 1 summarizes all the differences between the standard QuickC
  796.    interface and the expanded QuickC/QuickAssembler interface. Read this
  797.    chapter to learn how to enter, assemble, and run an assembly-language
  798.    program.
  799.  
  800.    Read Chapter 2 if you are new to 8086 assembly language or need to review
  801.    basic concepts. Chapter 2 explains the architecture of 8086-family
  802.    processors, as well as how to write simple code and data statements.
  803.  
  804.    Whether or not you're new to assembly language, you'll want to read
  805.    Chapters 3 and 4, which show the use of QuickAssembler's simplified
  806.    keywords in useful examples. These keywords make programming easier.
  807.  
  808.  
  809.  
  810.  
  811.  ────────────────────────────────────────────────────────────────────────────
  812.  Chapter 1:  The QuickAssembler Interface
  813.  
  814.  
  815.    After you install Microsoft QuickC with QuickAssembler, you'll have a
  816.    single environment for both compiling and assembling. You can create C
  817.    programs, assembly-language programs, and programs that combine both
  818.    languages.
  819.  
  820.    The environment completely supports the standard QuickC features,
  821.    including all editing commands as well as mouse, keyboard, and menu
  822.    techniques. This manual assumes you have read QuickC Up and Running and
  823.    have used the on-line Help system to learn how to use each menu. Refer to
  824.    these sources of information for basic help on using the interface.
  825.  
  826.    The combined QuickC/QuickAssembler interface provides some new menu
  827.    selections and dialog boxes to support development of assembly-language
  828.    programs. This chapter describes the new features, focusing on areas where
  829.    the interface adds new functionality: creating a program, building a
  830.    program, getting help, debugging, and viewing a listing file. To enable
  831.    all the features described in this chapter, you should first choose Full
  832.    Menus from the Options menu if you are not already using full menus.
  833.  
  834.  
  835.  1.1  Creating the Program
  836.  
  837.    Start the environment with the QC command, regardless of whether you're
  838.    creating a C or assembly-language source file. You can type QC by itself
  839.    or QC followed by the name of a file.
  840.  
  841.    By default, QC assumes that a file name on the command line has a .C
  842.    extension. You'll learn how to change this behavior later (by choosing
  843.    Display from the Options menu), but for now, make sure you include the
  844.    .ASM file extension when you want to create an assembly-language module:
  845.  
  846.    QC SAMPLE.ASM
  847.  
  848.    If the file is new, the QuickC/QuickAssembler environment asks you if you
  849.    would like to create the file.
  850.  
  851.    Once inside the QuickC/QuickAssembler environment, you can enter a program
  852.    by using all the QuickC editing commands. You can get started by entering
  853.    the following stand-alone assembly program. By default, QuickAssembler is
  854.    not case sensitive (except for external symbols), so you can enter
  855.    statements as uppercase or lowercase.
  856.  
  857.                .MODEL  small
  858.                .STACK
  859.                .CODE
  860.                .STARTUP
  861.                mov   ah,2
  862.                mov   dl,7
  863.                int   21h
  864.                mov   ax,4c00h
  865.                int   21h
  866.                END
  867.  
  868.    Enter the program above in a file with a .ASM extension. No other modules
  869.    and no special assembly or link flags are required. When run, the program
  870.    beeps and exits.
  871.  
  872.    For now, you may just want to run the program to see how the
  873.    QuickC/Quick-Assembler environment works. However, you can read the rest
  874.    of this section to get a brief explanation of why the program works.
  875.  
  876.    The four statements are directives──nonexecutable statements that give
  877.    basic structure to the program by declaring a memory model, stack segment,
  878.    and code segment.
  879.  
  880.    The next five statements perform the actions of the program. The first
  881.    three set up a call to a DOS function that prints the beep character. (The
  882.    QuickAssembler Advisor, which you access through the Help menu, provides
  883.    information on each DOS function.) The first three statements are shown
  884.    below, with comments:
  885.  
  886.                mov   ah,2     ; Move 2 to AH (select Print function)
  887.                mov   dl,7     ; Move 7 to DL (select Beep character)
  888.                int   21h      ; Call DOS function
  889.  
  890.    The next two statements, shown below with comments, call DOS to exit
  891.    gracefully. Unlike C programs, assembly-language programs must make an
  892.    explicit function call to exit, or else cause the processor to execute
  893.    meaningless instructions beyond the end of the program.
  894.  
  895.                mov   ax,4c00h ; Move 4c00h to AX (select Exit
  896.                               ;   function and 0 return code)
  897.                int   21h      ; Call DOS function
  898.  
  899.    The last statement ends the module.
  900.  
  901.  
  902.  1.2  Building and Running a Program
  903.  
  904.    Once inside the QuickC/QuickAssembler environment, you build an
  905.    assembly-language program the same way you build a C program. Choose the
  906.    Go command from the Run menu, or press the F5 key.
  907.  
  908.    The environment assembles and links the program if it needs to be built.
  909.    Then, if there are no errors, it executes the program. You can also
  910.    assemble a program by using the Make menu. The Compile File command
  911.    assembles your file rather than compiling it, assuming the current file
  912.    has a .ASM extension.
  913.  
  914.    To help you create assembly-language programs, the QuickC/QuickAssembler
  915.    interface adds the following extensions to QuickC:
  916.  
  917.    ■  A program list can now have .ASM files as well as .C, .OBJ, and .LIB
  918.       files if you work with multiple modules.
  919.  
  920.    ■  The Make dialog box from the Options menu has a new option button:
  921.       Assembler Flags.
  922.  
  923.    ■  The Assembler Flags dialog box lets you control how .ASM files are
  924.       assembled.
  925.  
  926.    If your program has multiple modules, you can add .ASM files to the
  927.    program list as well as other kinds of files. When you build the program,
  928.    the environment compiles each .C file module that needs to be built and
  929.    assembles each .ASM module that needs to be built.
  930.  
  931.    For example, the program list in Figure 1.1 creates a mixed-language
  932.    program with both C and assembly-language source files.
  933.  
  934.    ┌────────────────────────────────────────────────────────────────────────┐
  935.    │ This figure can be found in Section 1.2 of the manual                  │
  936.    └────────────────────────────────────────────────────────────────────────┘
  937.  
  938.    The environment sets the default file extension by looking at the
  939.    extension of the last file loaded. If the last file loaded had a .ASM
  940.    extension, the File List field now displays all the .ASM files for the
  941.    current directory. If the last file loaded had a .C extension, the File
  942.    List field displays all .C files.
  943.  
  944.    You can alter this behavior by choosing Display from the Options menu, as
  945.    explained in Section 1.4, "Choosing C or Assembler Defaults." In any
  946.    case, you can always control which files are displayed by entering a
  947.    wildcard expression, such as *.asm, in the File Name field.
  948.  
  949.    The environment lets you set assembler options as well as compiler
  950.    options. When you open the Options menu and choose Make, the dialog box
  951.    shown in Figure 1.2 appears.
  952.  
  953.    ┌────────────────────────────────────────────────────────────────────────┐
  954.    │ This figure can be found in Section 1.2 of the manual                  │
  955.    └────────────────────────────────────────────────────────────────────────┘
  956.  
  957.    This dialog box contains one new field: Assembler Flags. When you choose
  958.    this field, a new dialog box, shown in Figure 1.3, appears.
  959.  
  960.    ┌────────────────────────────────────────────────────────────────────────┐
  961.    │ This figure can be found in Section 1.2 of the manual                  │
  962.    └────────────────────────────────────────────────────────────────────────┘
  963.  
  964.    By setting flags in the Assembler Flags dialog box, you control the action
  965.    of the assembler whenever it builds a program. These settings have no
  966.    effect on .C modules, but do affect how each .ASM module is assembled.
  967.  
  968.    This dialog box contains a Debug Flags section, which has options that
  969.    apply only to Debug builds, and a Global Flags section, which has options
  970.    that apply to every build. Choose the Help button for an explanation of
  971.    each option.
  972.  
  973.    ──────────────────────────────────────────────────────────────────────────
  974.    NOTE  You control the type of build operation (Debug or Release) by
  975.    choosing the appropriate option button in the dialog box shown in Figure
  976.    1.2. You can return to that dialog box by choosing the OK or Cancel
  977.    command button. By choosing Debug (the default), you can use all of the
  978.    QuickC debugging commands while running the program. By choosing Release,
  979.    you produce a program that cannot be debugged but is somewhat smaller.
  980.    ──────────────────────────────────────────────────────────────────────────
  981.  
  982.    The Custom Flags section lets you enter additional options. In the three
  983.    Custom Flags text boxes, you can type any of the assembly options accepted
  984.    by the QCL driver. See Appendix B for a description of these options. The
  985.    next section describes how to use the QCL driver to assemble programs.
  986.  
  987.  
  988.  1.3  Assembling from the Command Line
  989.  
  990.    You can run QuickAssembler from the command line, just as you can run
  991.    QuickC. One utility, QCL, invokes both the assembler and compiler. You can
  992.    even use it to compile, assemble, and link mixed-language programs in one
  993.    step. However, make sure you use the version of QCL copied during
  994.    QuickAssembler installation.
  995.  
  996.    If you type a file name that has a .C extension, QCL invokes the C
  997.    compiler. For example, the following command compiles and links the file
  998.    SAMPLE1.C:
  999.  
  1000.    QCL SAMPLE1.C
  1001.  
  1002.    If you type a file name that has a .ASM extension, QCL invokes the
  1003.    QuickAssembler. For example, the following command assembles and links the
  1004.    file SAMPLE2.ASM:
  1005.  
  1006.    QCL SAMPLE2.ASM
  1007.  
  1008.    In any case, QCL links all resulting object files to create a .EXE file,
  1009.    unless you specify /c on the command line. (You can also create a .COM
  1010.    file if the program is written entirely in assembly language.) For
  1011.    example, the following command compiles SAMPLE1.C and assembles
  1012.    SAMPLE2.ASM, but does not link the resulting object files:
  1013.  
  1014.    QCL /c SAMPLE1.C /Cl SAMPLE2.ASM
  1015.  
  1016.    As always, you can specify .LIB files and .OBJ files on the QCL command
  1017.    line. A file with no extension is assumed to have a .OBJ extension by
  1018.    default. For example, the following QCL command compiles M1.C, assembles
  1019.    M2.ASM (with lowercase symbols preserved), and links M1.OBJ, M2.OBJ, and
  1020.    M3.OBJ. Finally, QCL searches M4.LIB for any unresolved references.
  1021.  
  1022.    QCL /Cx  M1.C  M2.ASM  M3  M4.LIB
  1023.  
  1024.    You can specify a number of QuickAssembler options, in addition to the
  1025.    ones provided specifically for C. See Appendix B, "Using Assembler
  1026.    Options with QCL," for a description of all these options.
  1027.  
  1028.  
  1029.  1.4  Choosing C or Assembler Defaults
  1030.  
  1031.    At all times, you can use the QuickC/QuickAssembler environment to create
  1032.    either C modules or assembly-language modules. However, there are some
  1033.    details of operation that make it a little easier to work with one
  1034.    language or another.
  1035.  
  1036.    For example, one consideration is whether the dialog box starts by
  1037.    displaying all the C files in the directory (*.c) or all the
  1038.    assembly-language files (*.asm) when you choose the Open command from the
  1039.    File menu. You can control this behavior by choosing Display from the
  1040.    Options menu. Figure 1.4 shows the dialog box that appears.
  1041.  
  1042.    ┌────────────────────────────────────────────────────────────────────────┐
  1043.    │ This figure can be found in Section 1.4 of the manual                  │
  1044.    └────────────────────────────────────────────────────────────────────────┘
  1045.  
  1046.    In the Language section of this dialog box, select either C, Assembler, or
  1047.    Auto. The Auto selection uses C or Assembler defaults, depending on what
  1048.    file was last loaded into the active window. For example, if you load the
  1049.    PROG.ASM file into the source window, all the defaults (described below)
  1050.    change to assembly-language settings.
  1051.  
  1052.    ──────────────────────────────────────────────────────────────────────────
  1053.    NOTE  When you first use QuickAssembler, the environment starts up in Auto
  1054.    mode. Thereafter, it looks at the settings in QC.INI to determine what
  1055.    mode to start in; this feature has the effect of saving display-mode
  1056.    settings between sessions.
  1057.    ──────────────────────────────────────────────────────────────────────────
  1058.  
  1059.    The following items change when the display mode changes──either because
  1060.    you change the mode manually or because you are in Auto mode and load a
  1061.    different kind of file:
  1062.  
  1063.    ■  For commands on the File menu, the default file name changes to *.c or
  1064.       *.asm.
  1065.  
  1066.    ■  The Include command on the View menu responds to .H files if the
  1067.       display mode is C, or .INC files if the display mode is Assembler.
  1068.  
  1069.    ■  The Index and Contents items from the Help menu bring up lists of
  1070.       topics for either C or Assembly, as determined by the display mode.
  1071.  
  1072.    Auto display mode assumes C defaults until you load a .ASM file. When you
  1073.    start the environment with the QC command, QC assumes that file names on
  1074.    the command line have .C extensions, unless the environment is in
  1075.    Assembler display mode.
  1076.  
  1077.  
  1078.  1.5  Using the Quick Advisor (Help)
  1079.  
  1080.    QuickAssembler extends the number of topics you can get information on,
  1081.    and updates QCENV.HLP so you can get context-sensitive help on the new
  1082.    menu items and dialog boxes. In addition, you still continue to get help
  1083.    on all of the C-language topics. The new topics, added for use with
  1084.    assembly language, are shown below:
  1085.  
  1086.    ■  QuickAssembler instructions
  1087.  
  1088.    ■  QuickAssembler directives and operators
  1089.  
  1090.    ■  DOS and ROM-BIOS services
  1091.  
  1092.    You can get help on assembly-language topics by using one of two different
  1093.    methods:
  1094.  
  1095.    1. Topical Help (press F1)
  1096.  
  1097.    2. The Help menu
  1098.  
  1099.    At all times, the expanded environment provides topical Help for both
  1100.    assembler and C keywords. Place the cursor on the keyword, then press F1.
  1101.    You can also get topical Help by moving the mouse cursor to the desired
  1102.    word and clicking the Right mouse button. The display mode (described in
  1103.    the previous section) determines whether C help files or assembly help
  1104.    files are searched first.
  1105.  
  1106.    ──────────────────────────────────────────────────────────────────────────
  1107.    NOTE  If the keyword starts with a dot (.), do not place the cursor on the
  1108.    dot or click on the dot to get topical Help. Place the cursor on the
  1109.    keyword or click on the keyword.
  1110.    ──────────────────────────────────────────────────────────────────────────
  1111.  
  1112.    QuickAssembler keywords include instructions, directives, and operators.
  1113.    Chapter 2, "Introducing 8086 Assembly Language" provides information on
  1114.    each of these concepts. An "instruction" is a specific action that the
  1115.    processor executes. Instructions are the primary building blocks of an
  1116.    assembly-language program.
  1117.  
  1118.    The Help screens on instructions are particularly useful, because they
  1119.    provide detailed information on timing, syntax, and processor flags. This
  1120.    manual features a topical discussion of instructions, but provides only
  1121.    limited information on timing and flags. To write the most efficient
  1122.    assembly-language programs, you should refer often to the on-line Help for
  1123.    instructions.
  1124.  
  1125.    To get help on DOS or ROM-BIOS services, select Contents or Index from the
  1126.    Help menu. These menu items give you help on assembly-language topics
  1127.    rather than C topics whenever the display mode (described in the previous
  1128.    section) is set to Assembler.
  1129.  
  1130.    The Help system offers other paths to get to information on DOS and BIOS
  1131.    functions. Move the mouse cursor to an interrupt number (such as 21H or
  1132.    33) and click the Right mouse button, or move the cursor to the number and
  1133.    press F1. The Help system responds by showing a screen listing of all the
  1134.    functions accessed through that interrupt number. You can then go to the
  1135.    specific Help screen you want. You can also get help on interrupt
  1136.    functions by selecting context-sensitive help for the INT keyword.
  1137.  
  1138.    You call these DOS and BIOS functions by using the INT instruction, as
  1139.    described in Chapter 4. These services perform basic input and output
  1140.    functions for you, giving you access to DOS and to hardware.
  1141.  
  1142.    By default, the Smart Help display option is on. This option makes the
  1143.    system more flexible by ignoring the presence or absence of a leading
  1144.    underscore (_) in front of a name. Consequently, pressing F1 while on
  1145.    _printf gives you help for the printf function.
  1146.  
  1147.  
  1148.  1.6  Debugging Assembly Code
  1149.  
  1150.    You can run a Debug build by choosing Debug in the dialog box opened by
  1151.    the Options menu's Make command. Debug is the default setting, so you
  1152.    probably won't need to choose it.
  1153.  
  1154.    You can use all of QuickC's debugging commands with programs written in
  1155.    assembly language. But keep in mind these considerations:
  1156.  
  1157.    ■  You must use an extra file with a .DBG file extension to debug programs
  1158.       in .COM format.
  1159.  
  1160.    ■  You must use C syntax to specify expressions to watch or modify, even
  1161.       when you debug assembly code. In addition, you can use the BY, WO, and
  1162.       DW memory operators, register names, and the colon (:) operator. The
  1163.       colon operator helps to specify segmented addresses.
  1164.  
  1165.    ■  When you trace execution of an assembly-language module, the behavior
  1166.       of the environment changes. Screen swapping is turned on by default,
  1167.       and the first line of code is never highlighted.
  1168.  
  1169.    ■  You can alter flag values and registers from within the environment.
  1170.  
  1171.    Sections 1.6.1-1.6.4 discuss each debugging feature in turn.
  1172.  
  1173.  
  1174.  1.6.1  Debugging .COM Files
  1175.  
  1176.    Section 4.8, "Creating .COM Files," explains how to use tiny memory
  1177.    model, along with a linker flag, to generate a program in the .COM-file
  1178.    format. A .COM file has a total size limitation of 64K, but is slightly
  1179.    smaller and loads faster than a similar .EXE file.
  1180.  
  1181.    When you run a Debug build that creates a .COM file, the linker places
  1182.    debugging information in a separate file with the same base name as the
  1183.    program and with a .DBG extension. If you delete the .DBG file, you cannot
  1184.    debug your program until you run another Debug build.
  1185.  
  1186.    Otherwise, all the considerations that apply to debugging .EXE files apply
  1187.    to .COM files as well.
  1188.  
  1189.  
  1190.  1.6.2  Specifying Expressions
  1191.  
  1192.    The Debug menu provides two commands──Watch Value and Watchpoint──that let
  1193.    you specify an expression for the QuickC/QuickAssembler environment to
  1194.    dynamically update and display. The environment displays the updated
  1195.    values in the Watch window. When you choose one of these commands, a
  1196.    dialog box appears, prompting you to enter an expression. Figure 1.5 shows
  1197.    the dialog box for the Watch Value command.
  1198.  
  1199.    ┌────────────────────────────────────────────────────────────────────────┐
  1200.    │ This figure can be found in Section 1.6.2 of the manual                │
  1201.    └────────────────────────────────────────────────────────────────────────┘
  1202.  
  1203.    You can enter any combination of variable names, constants, and C-language
  1204.    syntax. You cannot enter assembly-language keywords. However, the
  1205.    environment does recognize all valid register names (including names of
  1206.    both 8-bit and 16-bit registers). See Chapter 2, "Introducing 8086
  1207.    Assembly Language," for information on registers.
  1208.  
  1209.    In addition to register names, the expanded environment supports the
  1210.    optional use of the colon operator (:) for specifying segmented addresses:
  1211.  
  1212.    segment:offset
  1213.  
  1214.    In the syntax display above, segment can be a constant or a register;
  1215.    offset can be any expression. The QuickC/QuickAssembler environment
  1216.    combines the segment and offset addresses to determine a physical address,
  1217.    as described in Section 2.7, "Segmented Addressing and Segment
  1218.    Registers."
  1219.  
  1220.    The following examples demonstrate the use of the colon in valid
  1221.    expressions. Note that you use C-language syntax to specify hexadecimal
  1222.    numbers:
  1223.  
  1224.    0xb000:0x0000
  1225.    es:0x0100
  1226.    es:(array[2])
  1227.    ss:bp
  1228.  
  1229.    The QuickC/QuickAssembler environment considers a segmented-address
  1230.    expression to be a pointer to a character, which the Watch window
  1231.    evaluates by displaying the character pointed to. However, you can use
  1232.    QuickC type specifiers to alter how an expression is displayed. For
  1233.    example, the Watch window evaluates the following expression by displaying
  1234.    the numeric value of the address es:(warray+3):
  1235.  
  1236.    es:(warray+3),p
  1237.  
  1238.    You can use the three memory operators──BY, WO, and DW──to view the byte,
  1239.    word, or doubleword of memory at a given address.
  1240.  
  1241.    With pointer expressions and registers, BY returns the byte pointed to by
  1242.    the expression. (Segmented addresses are pointer expressions, as are
  1243.    procedure parameters declared with PTR.) With nonpointer variables, BY
  1244.    returns the byte at the same address as the variable. WO and DW work the
  1245.    same way, but return a word or doubleword, respectively.
  1246.  
  1247.    The rest of this section demonstrates how to use the three memory
  1248.    operators to specify useful expressions.
  1249.  
  1250.    To watch the contents of a register, enter just the register's name. To
  1251.    examine the value that the register points to, enter the BY, WO, and DW
  1252.    operators followed by the register name.
  1253.  
  1254.    Example             Value Specified
  1255.    ──────────────────────────────────────────────────────────────────────────
  1256.    bx                  The contents of the BX register
  1257.  
  1258.    BY bx               The byte pointed to by the BX register
  1259.  
  1260.    WO bx               The word pointed to by the BX register
  1261.  
  1262.    DW es:si            The doubleword pointed to by the SI register, relative
  1263.                        to the segment address in ES
  1264.  
  1265.  
  1266.    To watch the value of a variable, enter the variable's name. To watch the
  1267.    byte, word, or doubleword at the same address as the variable, use the BY,
  1268.    WO, and DW operators. In this context, these operators function as the
  1269.    QuickAssembler PTR operator does: they change the size of data to be
  1270.    examined. They are similar, but not identical, to C type casts. In the
  1271.    following examples, assume that Var is a word variable defined with DW:
  1272.  
  1273.    Example             Value Specified
  1274.    ──────────────────────────────────────────────────────────────────────────
  1275.    Var                 The variable Var (the word at the address of Var)
  1276.  
  1277.    BY Var              The byte at the address of Var
  1278.  
  1279.    DW Var              The doubleword at the address of Var
  1280.  
  1281.  
  1282.    You can use BY, WO, and DW to specify an array element, but you must
  1283.    understand that expressions in the Debug window are treated like C
  1284.    expressions rather than assembler expressions. As a result, the syntax you
  1285.    use to watch a memory location in the Debug window is often different from
  1286.    the syntax in your assembly source. For example, assume you have the
  1287.    following data and code:
  1288.  
  1289.    warr        DW     1, 2, 3, 4, 5, 6
  1290.                .
  1291.                .
  1292.                .
  1293.                mov    bx,0
  1294.                mov    cx,5
  1295.  
  1296.    loop1:      add    ax,warr[bx]
  1297.                add    bx,2
  1298.                loop   loop1
  1299.  
  1300.    You cannot watch the assembler expression warr[bx] directly. However, you
  1301.    can put an equivalent C expression in the Debug window:
  1302.  
  1303.    WO (char*)&warr + bx
  1304.  
  1305.    The address-of operator is necessary to make the C debugger look at the
  1306.    MASM array as a C array──that is, as an address. The value must cast to a
  1307.    character pointer because the debugger looks at it as a scaled C index
  1308.    rather than an unscaled assembler index. In this case, the assembler code
  1309.    adds 2 to the pointer BX to adjust for the variable size. You must tell
  1310.    the debugger to ignore its normal word scaling.
  1311.  
  1312.    Expressions are only scaled when there is a variable in the expression. In
  1313.    the expression WO BP+6 the 6 is not scaled──the expression means, "look at
  1314.    the word six bytes beyond the address that is in BP." However, in the
  1315.    expression WO &warr+6, the 6 is scaled because of the word size of the
  1316.    variable. Note that the variable size, not the expression type ( BY, WO,
  1317.    or DW), determines the size of scaling.
  1318.  
  1319.    If you are comfortable with C, you can also use C expressions to look at
  1320.    assembler expressions. Here are some examples you might find useful:
  1321.  
  1322.    Example             Value Specified
  1323.    ──────────────────────────────────────────────────────────────────────────
  1324.    &Var                The address of Var
  1325.  
  1326.    es:0x81,s           The string at es:[81h] (the DOS command line when a
  1327.                        program is started)
  1328.  
  1329.    &Arr[3]             The third element of an array (note that the 3 will be
  1330.                        scaled)
  1331.  
  1332.    *(&Arr+3)           Equivalent to the previous expression
  1333.  
  1334.  
  1335.  
  1336.  1.6.3  Tracing Execution
  1337.  
  1338.    The Run menu's Trace Into, Animate, and Step Over commands execute one
  1339.    statement of your program at a time. These commands are fully functional
  1340.    with assembly-language programs. However, debugging commands behave
  1341.    differently when you trace execution of an assembly-language module, as
  1342.    summarized below:
  1343.  
  1344.    ■  By default, screen swapping is on.
  1345.  
  1346.    ■  If the main module of the program is an assembly-language module, the
  1347.       first line of the program is never highlighted.
  1348.  
  1349.    ■  The Calls menu does not function unless you write your program
  1350.       according to certain guidelines.
  1351.  
  1352.    The rest of this section elaborates on these differences.
  1353.  
  1354.    When you trace execution of an assembly-language module, screen swapping
  1355.    is turned on. The environment does not support an Auto screen-swapping
  1356.    mode for assembly-language programs because it cannot detect when a
  1357.    program writes to the screen. Therefore, when executing a .ASM file, the
  1358.    environment equates the Auto screen-swapping selection with screen
  1359.    swapping turned on.
  1360.  
  1361.    You can always turn screen swapping off manually by choosing the Run/Debug
  1362.    command from the Options menu. When a dialog box appears, choose the Off
  1363.    option button in the Screen Swapping field.
  1364.  
  1365.    Screen swapping causes the environment to switch to a full output screen
  1366.    each time the program executes code. The effect is particularly noticeable
  1367.    when you choose the Animate command. Leaving screen swapping on preserves
  1368.    program output. However, if large portions of your program do not write to
  1369.    the video display, you may want to turn screen swapping off temporarily.
  1370.  
  1371.    The second debugging feature that operates differently for assembly-
  1372.    language programs is current-line highlighting. When you restart a
  1373.    program, the environment does not highlight the first line of code. The
  1374.    debugging facility does not know which line of code is the first to be
  1375.    executed, since this information is stored in the executable-file header.
  1376.    After you execute a trace, the second program line is highlighted, and
  1377.    thereafter current-line highlighting works as you would expect.
  1378.  
  1379.    The third feature that operates differently is the Calls command from the
  1380.    Debug menu. To ensure that the command works with assembly-language
  1381.    modules, either use the PROC directive with an argument list or local
  1382.    variables, as described in Chapter 3, "Writing Assembly Modules for C
  1383.    Programs," or else set up the framepointer (the BP register) as described
  1384.    in Appendix A, "Mixed-Language Mechanics." Both these methods set up a
  1385.    stack frame for each procedure, using the standard Microsoft methods. The
  1386.    environment checks stack frames to see what procedures have been called,
  1387.    and with what parameters.
  1388.  
  1389.  
  1390.  1.6.4  Modifying Registers and Flags
  1391.  
  1392.    With the expanded QuickC/QuickAssembler environment, you can get much
  1393.    greater use from the Registers window. The Registers window displays more
  1394.    information than it does in the simple QuickC environment, and you can
  1395.    also use the window to alter register and flag values.
  1396.  
  1397.    ──────────────────────────────────────────────────────────────────────────
  1398.    NOTE  By default, the environment does not display the Registers window.
  1399.    To open this window, choose the Window command from the View menu. A
  1400.    dialog box appears that lists all windows. Move the cursor to Registers
  1401.    and press the ENTER key, or move the mouse cursor to Registers and double
  1402.    click the Left mouse button. To close the window, repeat the procedure.
  1403.    ──────────────────────────────────────────────────────────────────────────
  1404.  
  1405.    The Registers window displays the contents of both 8086 and 8087
  1406.    registers. You can remove 8087 registers from the Registers window by
  1407.    choosing Display from the Options menu. When the dialog box appears, turn
  1408.    the Show 8087 option button off. The environment only displays 8087
  1409.    registers if you have a math coprocessor or have a program that calls
  1410.    floating-point emulator routines from a high-level language.
  1411.  
  1412.    You can alter values in the window by either using the mouse or the
  1413.    keyboard. To alter a value, you first select the item you want to change:
  1414.  
  1415.    ■  To alter a value with the mouse, select an item by clicking the Left
  1416.       mouse button.
  1417.  
  1418.    ■  To alter a value with the keyboard, first place the cursor on an item
  1419.       in the window. (Press TAB or SHIFT+TAB to cycle quickly through the
  1420.       items.) Then select the item by pressing the ENTER key. The List field
  1421.       has no function in this context and should be ignored.
  1422.  
  1423.    Choosing a flag toggles the flag to the opposite setting. Choosing a
  1424.    register brings up a dialog box. Type the new value for the register and
  1425.    press ENTER.
  1426.  
  1427.  
  1428.  1.7  Viewing a Listing File
  1429.  
  1430.    When you assemble a module with the Debug build setting (the default),
  1431.    QuickAssembler can create a listing file. Choose the type of listing by
  1432.    using the Assembler Flags dialog box. (To access this dialog box, choose
  1433.    Make from the Options menu, then choose Assembler Flags.) You should also
  1434.    make sure that the One Pass Assembly option is not selected.
  1435.  
  1436.    A QuickAssembler listing file shows precisely how the assembler translated
  1437.    each line of code during the last program build. Each instruction in the
  1438.    source code is listed next to its corresponding numeric code (machine
  1439.    instruction).
  1440.  
  1441.    Listing files are particularly useful if your program uses macro calls or
  1442.    include files. The listing file displays each statement generated by a
  1443.    macro call and each line of code copied from an include file. Tables at
  1444.    the end of the listing file give information on macros, symbols,
  1445.    structures, groups, and records. Part 2 of this manual describes each of
  1446.    these features of assembly language.
  1447.  
  1448.    To view the listing file, assemble the source code at least once. You can
  1449.    view the listing file for the current module by choosing the Listing
  1450.    command from the View menu. You can also view the file with the CTRL+F2
  1451.    shortcut key.
  1452.  
  1453.    The listing file is then displayed in the Source window, as shown in
  1454.    Figure 1.6. You can page through this file by using all the normal
  1455.    cursor-movement commands. When you want to return to the previous file,
  1456.    press F2 or use the File menu. You can also leave the listing file by
  1457.    choosing the Listing command again; this action causes the environment to
  1458.    switch to the original line of source code that generated the current line
  1459.    of code. In particular, if you are in a listing file and move the cursor
  1460.    to a line generated from an include file (.INC), the Listing command
  1461.    switches directly to that include file.
  1462.  
  1463.    ┌────────────────────────────────────────────────────────────────────────┐
  1464.    │ This figure can be found in Section 1.7 of the manual                  │
  1465.    └────────────────────────────────────────────────────────────────────────┘
  1466.  
  1467.    Normally, you would choose the Listing command when in a .LST file or in a
  1468.    .ASM file with a corresponding .LST file (previously generated by a
  1469.    program build). If you are not in either of these types of files, the
  1470.    environment responds by displaying a dialog box for opening a file; *.lst
  1471.    is the default file name.
  1472.  
  1473.  
  1474.  
  1475.  ────────────────────────────────────────────────────────────────────────────
  1476.  Chapter 2:  Introducing 8086 Assembly Language
  1477.  
  1478.  
  1479.    Assembly-language programs control hardware directly, giving you the
  1480.    ability to write the fastest, smallest programs possible and to execute
  1481.    any operation. But assembly-language programming also requires an
  1482.    understanding of the architecture of 8086-family processors.
  1483.  
  1484.    Assembly language is close to machine code──the processor's numeric
  1485.    language of 1's and 0's. Each QuickAssembler instruction corresponds to an
  1486.    8086 instruction but consists of a meaningful name (mnemonic) instead of a
  1487.    number. For example, the ADD instruction computes the sum of two items.
  1488.    QuickAssembler translates this instruction to produce a numeric code, such
  1489.    as 10000010 binary. The processor responds to this code when you run the
  1490.    program.
  1491.  
  1492.    This process of translation is called "assembling." Before you can
  1493.    assemble a program, you need to understand the basic concepts of the
  1494.    processor and of assembly language. This chapter presents these concepts.
  1495.  
  1496.  
  1497.  2.1  Programming the 8086 Family
  1498.  
  1499.    If you have programmed in C, you can get a good grasp of 8086 assembly
  1500.    language by focusing on the differences between the two languages:
  1501.  
  1502.    1. A C statement may combine many complex operations, but each line of
  1503.       assembly language specifies just one limited action called an
  1504.       "instruction." QuickAssembler also supports a number of nonexecutable
  1505.       statements called "directives," which provide structure to the program,
  1506.       declare data objects, and provide other information.
  1507.  
  1508.       Sections 2.2-2.4 explain the basics of writing instructions and
  1509.       directives.
  1510.  
  1511.    2. C programs deal with memory locations (known as variables), but
  1512.       assembly-language programs must deal with registers as well. A
  1513.       "register" is a special memory location inside the processor itself,
  1514.       having a permanent name rather than a numeric address.
  1515.  
  1516.       Section 2.5, "8086-Family Registers," describes the use of each
  1517.       register.
  1518.  
  1519.    3. A data object in a C program can be arbitrarily complicated.
  1520.       Assembly-language statements work on objects accessed through four
  1521.       specific modes: immediate, register, direct memory, and indirect
  1522.       memory. Each mode has specific properties and limitations imposed by
  1523.       the processor.
  1524.  
  1525.       Section 2.6, "Addressing Modes," explains each of these four modes and
  1526.       gives examples.
  1527.  
  1528.    4. The processor combines two 16-bit addresses to access each memory
  1529.       location. This mechanism is called "segmented addressing." Assembly
  1530.       language often requires a more complete understanding of segmented
  1531.       addressing than C does.
  1532.  
  1533.       Section 2.7, "Segmented Addressing and Segment Registers," explains
  1534.       the full implications of segmented addressing.
  1535.  
  1536.    Of the features listed above, segmented addressing is unique to the 8086
  1537.    family. The 8086 is further distinguished from other processors by its set
  1538.    of string operations, which permit fast initialization and copying of
  1539.    blocks of data. You can read more about the string operations in Chapter
  1540.    16, "Processing Strings."
  1541.  
  1542.  
  1543.  2.2  Instructions, Directives, and Operands
  1544.  
  1545.    The 8086-family processors understand only one kind of statement: an
  1546.    instruction. QuickAssembler understands two kinds of statements:
  1547.    instructions and directives.
  1548.  
  1549.    As explained above, an instruction corresponds to a specific action that
  1550.    the processor executes at run time. The fundamental task of the assembler
  1551.    is to correctly translate each of these statements to specific
  1552.    machine-code instructions.
  1553.  
  1554.    As nonexecutable statements, directives are not translated to machine
  1555.    actions. However, they give information to the assembler that affects how
  1556.    other statements are translated. For example, some of the most important
  1557.    directives declare data. These directives, in turn, help the assembler
  1558.    correctly interpret instructions that refer to the data.
  1559.  
  1560.    The rest of this section explains each part of an assembly-language
  1561.    statement; the general syntax applies to both instructions and directives.
  1562.    The section ends by stating the basics of entering numbers in different
  1563.    radixes.
  1564.  
  1565.    Syntax
  1566.  
  1567.    Each line of source code consists of a blank line or a statement. Each
  1568.    statement is an instruction or directive, and can contain as many as 512
  1569.    characters. Statements can have up to four fields, as shown below:
  1570.  
  1571.    [[name]] [[operation]] [[operands]] [[;comment]]
  1572.  
  1573.    Each field (except the comment field) must be separated from the other
  1574.    fields by a space or tab character. You can enter statements in uppercase
  1575.    or lowercase letters. By default, QuickAssembler is not case sensitive,
  1576.    but it does preserve case for external variables──thus providing
  1577.    compatibility with C, which is case sensitive. You can control case
  1578.    sensitivity by using the Assembler Flags dialog box.
  1579.  
  1580.    As a convention, sample code in this manual uses uppercase letters for
  1581.    directives, hexadecimal letter digits, and segment definitions.
  1582.  
  1583.  
  1584.  2.2.1  The Name Field
  1585.  
  1586.    The name field labels the statement with a symbolic name that other parts
  1587.    of the program can reference. The meaning of the name depends on the type
  1588.    of statement.
  1589.  
  1590.    One of the most important uses of this field occurs in data declarations.
  1591.    These declarations are much like variable declarations in C. The statement
  1592.    defines the type and initial value. You use the name elsewhere in the
  1593.    program, when you want to access the data.
  1594.  
  1595.    QuickAssembler is different from C, however, in that the symbolic name
  1596.    occurs in the first field. For example, the following DB directive
  1597.    (Declare Bytes) associates the name string with a series of characters:
  1598.  
  1599.    string      DB    "Hello, world"
  1600.  
  1601.    In instructions, the name field functions like a program label in C: it
  1602.    provides a target for a jump or call instruction elsewhere in the program.
  1603.  
  1604.    To label an instruction, follow the name field with a colon (:). You can
  1605.    place the name on the same line as the rest of the instruction or, to
  1606.    improve readability, on a separate line. The following example shows the
  1607.    latter case:
  1608.  
  1609.    top:                    ; This label marks the top of the loop
  1610.                mov   ax,1  ; This is first instruction in the loop
  1611.  
  1612.    There are other ways to label instructions. See Section 6.4, "Defining
  1613.    Code Labels," for more information on how to declare labels.
  1614.  
  1615.  
  1616.  2.2.2  The Operation Field
  1617.  
  1618.    The operation field states the action of the statement. This field
  1619.    determines the fundamental type of the statement──instruction or
  1620.    directive. It also determines what additional syntax, if any, is required.
  1621.    Some operations require an entry in the name field; most do not. If the
  1622.    operation is an instruction, it strictly determines how many and what kind
  1623.    of operands are legal.
  1624.  
  1625.    This field contains exactly one item──an instruction or directive
  1626.    mnemonic. "Mnemonics" are abbreviated, easy-to-remember names that each
  1627.    symbolize a different operation (for instance, ADD, SUB, and OR). Examples
  1628.    of directive mnemonics include EQU (Equate) and DB (Declare Bytes).
  1629.  
  1630.  
  1631.  2.2.3  The Operand Field
  1632.  
  1633.    The operand field lists the objects on which the statement operates.
  1634.    Multiple operands are separated by commas. These objects can be registers,
  1635.    constants, or memory locations. A memory location is typically represented
  1636.    as a variable, although it can also be expressed as a numeric address or
  1637.    complex expression.
  1638.  
  1639.    Registers and constants require no previous declaration. To refer to a
  1640.    variable, however, you should first declare the name with a data
  1641.    directive, such as DB (Declare Bytes). The following example declares the
  1642.    variable count and then uses it in an instruction:
  1643.  
  1644.     count      DB      7       ; Declare count as a byte variable
  1645.                .
  1646.                .
  1647.                .
  1648.                inc     count   ; count = count + 1
  1649.  
  1650.    In the first statement, count appears in the name field and the number 7
  1651.    appears in the operand field. The DB directive associates count with the
  1652.    address of a byte initialized to 7. In the second statement, count appears
  1653.    in the operand field. The INC instruction (increment) adds 1 to count,
  1654.    thus increasing the value of the data to 8.
  1655.  
  1656.    The next section gives more information on how to declare memory locations
  1657.    as data types. Section 2.6, "Addressing Modes," gives a complete
  1658.    description of all the different methods for specifying operands.
  1659.  
  1660.  
  1661.  2.2.4  The Comment Field
  1662.  
  1663.    The comment field lets you add text that appears in source code but is
  1664.    ignored by the assembler. You can enter any text you want in this field.
  1665.    Typically, you would use it to document the purpose of the statement. The
  1666.    purpose of an assembly-language statement is not always self-explanatory,
  1667.    and for this reason, programs often contain at least one comment for each
  1668.    instruction.
  1669.  
  1670.    Single-line comments always begin with a semicolon (;). You can also
  1671.    create a multiline comment by one of two methods. You can enter successive
  1672.    comment lines as shown below:
  1673.  
  1674.                add     count,5    ; Add 5 to count.
  1675.                                   ;   ADD is the operation.
  1676.                                   ;   count and 5 are operands.
  1677.                sub     Sum,12     ; Subtract 12 from Sum.
  1678.                                   ;   SUB is the operation.
  1679.                                   ;   Sum and 12 are operands.
  1680.  
  1681.    You can also use the COMMENT directive, which lets you enter multiline
  1682.    comments without using the semicolon. This directive has the following
  1683.    syntax:
  1684.  
  1685.    COMMENT delimiter [[text]]
  1686.    text
  1687.    [[text]] delimiter [[text]]
  1688.  
  1689.    All text between the first delimiter and the line containing a second
  1690.    delimiter is ignored by the assembler. The delimiter character is the
  1691.    first nonblank character after the COMMENT directive. The text includes
  1692.    the comments up to and including the line containing the next occurrence
  1693.    of the delimiter.
  1694.  
  1695.    Example
  1696.  
  1697.                COMMENT + The plus
  1698.                        sign is the delimiter. The
  1699.                        assembler ignores the statement
  1700.                        following the last delimiter
  1701.    +           mov     ax,1   (ignored)
  1702.  
  1703.  
  1704.  2.2.5  Entering Numbers in Different Bases
  1705.  
  1706.    As with C, you can enter assembly-language constants as decimal,
  1707.    hexadecimal, or octal. You can also enter binary constants. By default,
  1708.    all constants are decimal, but you specify a different default with the
  1709.    RADIX directive.
  1710.  
  1711.    Hexadecimal constants appear frequently in assembly-language programs. To
  1712.    indicate a hexadecimal constant, add an uppercase or lowercase H suffix.
  1713.    If the first digit is one of the letters A-F, prefix the constant with a
  1714.    leading 0 to indicate that the number is not a symbolic name.
  1715.  
  1716.    Examples
  1717.  
  1718.    100H
  1719.    10FAh
  1720.    0be03H
  1721.    0FFh
  1722.  
  1723.    You may often want to enter binary constants as well, particularly when
  1724.    constructing bit masks. To indicate a binary constant, simply add an
  1725.    uppercase or lowercase B suffix.
  1726.  
  1727.    For more information on using different bases and using the RADIX
  1728.    directive, see Section 6.1.1.2, "Setting the Default Radix."
  1729.  
  1730.  
  1731.  2.2.6  Line-Continuation Character
  1732.  
  1733.    You can create program lines that extend over more than one physical line
  1734.    by using the backslash (\) as a line-continuation character. The backslash
  1735.    must be the last character on the line. Comments cannot follow it. A
  1736.    backslash is not considered a continuation character if it occurs in a
  1737.    comment.
  1738.  
  1739.    Example
  1740.  
  1741.    BigProc     PROC FAR \
  1742.                USES DS SI DI, \
  1743.                IntArg:WORD, \
  1744.                String:FAR PTR BYTE, \
  1745.                Ptr:FAR PTR BIGSTRUC, \
  1746.                Long:DWORD
  1747.                .
  1748.                .
  1749.                .
  1750.  
  1751.                ret
  1752.    BigProc     ENDP
  1753.  
  1754.    In this example, the line continuation-character is used to specify
  1755.    multiple procedure arguments with the extended PROC syntax. All the
  1756.    arguments must be placed on a single logical line, but they would go past
  1757.    the edge of the editor screen if not placed on separate lines. The
  1758.    continuation character is also useful for long macro calls and data
  1759.    initializations.
  1760.  
  1761.  
  1762.  2.3  8086-Family Instructions
  1763.  
  1764.    The 8086-family processors support more than 80 instructions, but you
  1765.    don't need to memorize the entire instruction set. Once inside the
  1766.    expanded QuickC environment, you can get instant information on any
  1767.    instruction. Move the cursor to an instruction keyword on the screen, then
  1768.    press F1. To find the appropriate instruction for the action you want to
  1769.    perform, refer to Part 3 of this book, which provides a topical survey of
  1770.    instructions.
  1771.  
  1772.    Many programs can be written with just a few of the most common
  1773.    instructions. Sections 2.3.1 and 2.3.2 introduce some of these
  1774.    instructions, grouping them into two sets: instructions that manipulate
  1775.    data and instructions that control program flow. The programs in Chapters
  1776.    3 and 4 use these same instructions to illustrate basic concepts of 8086
  1777.    assembly language.
  1778.  
  1779.  
  1780.  2.3.1  Data-Manipulation Instructions
  1781.  
  1782.    The first group of instructions manipulate data. Each causes the processor
  1783.    to copy data or perform a calculation at run time. Some of the simpler C
  1784.    statements translate directly into a single instruction, so this section
  1785.    uses C statements for illustration. Here are the six basic data-
  1786.    manipulation instructions introduced in this section:
  1787.  
  1788.    ■  MOV (move data)
  1789.  
  1790.    ■  ADD (add second operand to first)
  1791.  
  1792.    ■  SUB (subtract second operand from first)
  1793.  
  1794.    ■  INC (increment operand)
  1795.  
  1796.    ■  DEC (decrement operand)
  1797.  
  1798.    ■  MUL (integer multiplication)
  1799.  
  1800.    The processor supports a great many other data-manipulation instructions,
  1801.    which are covered in Part 3 of this manual.
  1802.  
  1803.  
  1804.  2.3.1.1  The MOV Instruction
  1805.  
  1806.    The MOV instruction, probably the most frequently used 8086 instruction,
  1807.    copies data from one location to another. The instruction leaves the
  1808.    source data unaffected, so it is more a copy than a move. The MOV
  1809.    instruction takes two operands:
  1810.  
  1811.    MOV destination,source
  1812.  
  1813.    The instruction copies the value of the source to the destination. It
  1814.    might seem more logical to place the source operand first, until you
  1815.    consider that C and BASIC assignments use the same order. For example, the
  1816.    instruction
  1817.  
  1818.    mov   count,5
  1819.  
  1820.    places the value 5 at the memory location count and thus performs the same
  1821.    action as the C statement
  1822.  
  1823.    count = 5;
  1824.  
  1825.    The destination operand is similar to an "lvalue" in C. Instructions that
  1826.    have two operands always interpret the leftmost operand as the
  1827.    destination, or lvalue. The destination is the operand that the
  1828.    instruction can alter; thus, it can't be a constant. Another limitation on
  1829.    instructions with two operands is that the operands cannot both be memory
  1830.    locations.
  1831.  
  1832.  
  1833.  2.3.1.2  The ADD Instruction
  1834.  
  1835.    The ADD instruction, like MOV, takes two operands: a destination and a
  1836.    source. The processor adds the two operands together, storing the result
  1837.    in the destination (on the left). This action will be familiar to C
  1838.    programmers, since the instruction
  1839.  
  1840.    add  sum,10
  1841.  
  1842.    adds 10 to the memory location sum and thus performs the same action as
  1843.    the C statement
  1844.  
  1845.    sum += 10;
  1846.  
  1847.    The 8086 does not perform automatic scaling for pointer addition as C
  1848.    does. The program itself must perform scaling for all pointer arithmetic.
  1849.  
  1850.  
  1851.  2.3.1.3  The SUB Instruction
  1852.  
  1853.    The SUB instruction is the counterpart of ADD: it subtracts the source
  1854.    operand from the destination operand, storing the result in the
  1855.    destination (on the left). Thus, the instruction
  1856.  
  1857.    sub  total,7
  1858.  
  1859.    performs the same action as the C statement
  1860.  
  1861.    total -= 7;
  1862.  
  1863.  
  1864.  2.3.1.4  The INC and DEC Instructions
  1865.  
  1866.    The INC (Increment) and DEC (Decrement) instructions add and subtract 1,
  1867.    respectively. They are similar to, but faster than, ADD and SUB, and are
  1868.    provided because adding and subtracting by 1 are such common operations.
  1869.    The instruction
  1870.  
  1871.    inc   count
  1872.  
  1873.    performs the same action as the C statement
  1874.  
  1875.    count++;
  1876.  
  1877.  
  1878.  2.3.1.5  The AND Instruction
  1879.  
  1880.    The AND instruction is one of several bitwise logic operations supported
  1881.    by the 8086. AND provides an efficient way to mask out bits. The
  1882.    instruction
  1883.  
  1884.    and   stuff,0FFF0h
  1885.  
  1886.    masks out the four lowest bits of stuff, as does the C statement
  1887.  
  1888.    stuff &= 0x0FFF0;
  1889.  
  1890.  
  1891.  2.3.1.6  The MUL Instruction
  1892.  
  1893.    The MUL instruction multiplies two items, but one of these items is an
  1894.    "implied operand"──that is, an operand you do not specify. For example,
  1895.    the 16-bit version of the MUL instruction takes one explicit 16-bit
  1896.    operand:
  1897.  
  1898.    mul   factor
  1899.  
  1900.    The other operand is the AX register. The processor multiplies factor by
  1901.    the value of AX, storing the low 16 bits of the result in AX. The
  1902.    description of the AX register in Section 2.5.1, "The General-Purpose
  1903.    Registers," gives more information on MUL.
  1904.  
  1905.  
  1906.  2.3.2  Control-Flow Instructions
  1907.  
  1908.    The control-flow instructions enable the program to execute loops and to
  1909.    make decisions. Some of these instructions transfer control of the program
  1910.    to a new address. The conditional jump instructions let you provide
  1911.    program logic: they look at the result of a previous operation, and then
  1912.    decide whether to jump or not. Here are the five basic control-flow
  1913.    instructions introduced in this section:
  1914.  
  1915.    ■  JMP (Jump unconditionally)
  1916.  
  1917.    ■  CMP (Compare──subtract without storing result)
  1918.  
  1919.    ■  JE (Jump If Equal)
  1920.  
  1921.    ■  JA (Jump If Above)
  1922.  
  1923.    ■  JB (Jump If Below)
  1924.  
  1925.    The processor supports a number of other control-flow instructions,
  1926.    including several conditional jumps. See Section 15.1.2, "Jumping
  1927.    Conditionally," for a description of these instructions.
  1928.  
  1929.  
  1930.  2.3.2.1  The JMP Instruction
  1931.  
  1932.    The JMP instruction causes the processor to jump to a new program address.
  1933.    Like the C goto statement, JMP takes one operand: a label associated with
  1934.    another statement. The instruction
  1935.  
  1936.    jmp   begin
  1937.  
  1938.    jumps to the label begin, and thus performs the same action as the C
  1939.    statement
  1940.  
  1941.    goto begin;
  1942.  
  1943.  
  1944.  2.3.2.2  The CMP Instruction
  1945.  
  1946.    The CMP instruction, like SUB, performs a subtraction. But CMP doesn't
  1947.    store the result; instead, it just sets processor flags in preparation for
  1948.    a conditional jump (such as JE, JA, or JB).
  1949.  
  1950.    A "processor flag" is a bit that resides in the processor and indicates
  1951.    whether a specific condition is on or off. For example, the Zero flag
  1952.    indicates that the result of the last operation produced zero. The JE
  1953.    instruction (Jump If Equal) checks this one flag only, jumping if it is
  1954.    set. Other conditional jumps determine a result by checking a combination
  1955.    of flag settings. See Section 2.5.4, "The Flags Register," for a
  1956.    description of all the flags.
  1957.  
  1958.    Many instructions, including SUB, set processor flags. However, some of
  1959.    these instructions have strong side effects. Use ADD or SUB to prepare for
  1960.    a conditional jump when convenient. But use CMP when you need to make a
  1961.    simple comparison without altering data.
  1962.  
  1963.  
  1964.  2.3.2.3  The Conditional Jump Instructions
  1965.  
  1966.    The JE, JA, and JB instructions are conditional jumps (meaning Jump On
  1967.    Equal, Jump If Above, and Jump If Below, respectively). Like JMP, they
  1968.    each take one argument: a program label to which to jump. Unlike JMP, they
  1969.    cause the processor to jump only when certain flag settings are detected.
  1970.    The result is that when you use CMP in combination with a conditional jump
  1971.    instruction, you create an if-then relationship similar to an if statement
  1972.    in a high-level language. Consider the following instructions:
  1973.  
  1974.                cmp     sum,10       ; Compare sum to 10
  1975.                ja      top          ; If sum > 10, jump to top
  1976.  
  1977.    This logic is a little different from a C program. The first instruction
  1978.    makes the comparison. The second states, "If the result of the previous
  1979.    instruction was above zero, then jump." Taken together, these two
  1980.    instructions perform the same action as the C statement
  1981.  
  1982.    if( sum > 10 )
  1983.        goto top;
  1984.  
  1985.    Of course, most C programmers do not use many goto statements. Typically,
  1986.    you would test for a condition and execute a series of statements if the
  1987.    condition is true, as in the following code:
  1988.  
  1989.    if( sum >= 10 )
  1990.    {
  1991.        sum = 1;
  1992.        count += 2;
  1993.        delta = 5;
  1994.    }
  1995.  
  1996.    To implement this code in assembly language, test for the opposite
  1997.    condition, then jump past statements if they should not be executed. For
  1998.    example, the following code executes the three statements inside the if
  1999.    block only if sum is greater than or equal to 10:
  2000.  
  2001.    TopOfBlock:
  2002.                cmp     sum,10           ; Compare sum to 10
  2003.                jb      SumNotGreater    ; If sum < 10, do NOT do
  2004.                                         ;   next three statements
  2005.                mov     sum,1            ; sum = 1
  2006.                add     count,2          ; count = count + 2
  2007.                mov     delta,5          ; delta = 5
  2008.    SumNotGreater:
  2009.  
  2010.    ──────────────────────────────────────────────────────────────────────────
  2011.    NOTE  JA (Jump If Above) and JB (Jump If Below) each work properly when
  2012.    you compare unsigned integers. To compare signed integers, use JG (Jump If
  2013.    Greater) and JL (Jump If Less Than). See Section 15.1.2, "Jumping
  2014.    Conditionally," for a complete list of conditional jump instructions.
  2015.    ──────────────────────────────────────────────────────────────────────────
  2016.  
  2017.  
  2018.  2.4  Declaring Simple Data Objects
  2019.  
  2020.    This section describes how to declare global variables──often called
  2021.    "static" because each corresponds to a fixed memory location.
  2022.  
  2023.    Programs generally require data. If you wrote a program in machine code,
  2024.    you'd have to reserve locations in memory for data, determine the address
  2025.    of each data object, and remember these addresses whenever you operated on
  2026.    memory. Fortunately, the assembler reserves memory locations for you and
  2027.    associates each location with a symbolic name.
  2028.  
  2029.    You use data directives to tell the assembler how to allocate and refer to
  2030.    memory. The most common data directives for characters and integers are:
  2031.  
  2032.    Directive           Description
  2033.    ──────────────────────────────────────────────────────────────────────────
  2034.    DB                  Declare byte (either a small integer or a character)
  2035.  
  2036.    DW                  Declare word (2-byte integer)
  2037.  
  2038.    DD                  Declare doubleword (4-byte integer)
  2039.  
  2040.  
  2041.    To use these directives, place the name of the variable first, then enter
  2042.    the data directive. The third column (operand field) contains one or more
  2043.    initial values. Use a question mark to indicate an item with no initial
  2044.    value.
  2045.  
  2046.    aByte       DB    1    ; aByte is a 1-byte integer, initialized to 1
  2047.    area        DW    500  ; area is a 2-byte integer, initialized to 500
  2048.    population  DD    ?    ; population is a 4-byte integer, no initial value
  2049.  
  2050.    These directives correspond roughly to the following C statements:
  2051.  
  2052.    char    aByte = 1;
  2053.    int     area = 500;
  2054.    long    population;
  2055.  
  2056.    Assembly data declarations are different from C declarations, however, in
  2057.    that assembly data declarations are not declared signed or unsigned.
  2058.    Instead, you must remember whether you intend to treat a variable as
  2059.    signed or unsigned, and choose the appropriate operations.
  2060.  
  2061.    Data directives reserve memory in the object file. They also associate
  2062.    each variable with a name and a size attribute.
  2063.  
  2064.    The assembler uses this information to correctly assemble instructions
  2065.    that operate on variables. For example, at the machine-code level, the INC
  2066.    instruction can be encoded to increment either a byte or a word of data.
  2067.    The way the assembler encodes the instruction
  2068.  
  2069.                inc     myvar
  2070.  
  2071.    depends on whether myvar was declared as a byte or word. (If it was
  2072.    declared a doubleword, the instruction is illegal.) Another important use
  2073.    of size attributes is in checking the validity of two operands. For
  2074.    example, the following instruction causes the assembler to print a warning
  2075.    message, because aByte and bx do not share the size attribute:
  2076.  
  2077.                mov     bx,aByte    ; Move aByte into a word register
  2078.  
  2079.    Moving a byte into a word location is not possible. After issuing the
  2080.    warning, the assembler adjusts the instruction as if it were written as
  2081.    follows:
  2082.  
  2083.                mov     bx,WORD PTR aByte  ; Move the word at aByte to BX
  2084.  
  2085.    The PTR operator temporarily modifies the size attribute of the object
  2086.    that follows it. PTR can be used with a number of different data types, as
  2087.    shown below:
  2088.  
  2089.    Keywords            Refers to
  2090.    ──────────────────────────────────────────────────────────────────────────
  2091.    BYTE PTR object     The byte at address of object
  2092.  
  2093.    WORD PTR object     The word at address of object
  2094.  
  2095.    DWORD PTR object    The doubleword at address of object
  2096.  
  2097.  
  2098.    However, this adjustment may not produce the action you really want. The
  2099.    PTR operator is not quite the same as a type cast in C. The C (int) type
  2100.    cast manipulates data so that it represents the same value, but in a
  2101.    different format. WORD PTR does no data manipulation──it simply causes the
  2102.    instruction to operate on the word at the given address. In the example
  2103.    above, the use of WORD PTR causes two adjacent bytes of data to be loaded
  2104.    from memory into BX. If what you really want is to move a single byte of
  2105.    data to BX, but convert it to a word, use the following code:
  2106.  
  2107.                mov     bl,aByte            ; Lower byte of BX = aByte
  2108.                sub     bh,bh               ; Higher byte of BX = 0
  2109.  
  2110.    The example above only works properly when handling unsigned numbers. When
  2111.    working with signed quantities, use the CBW instruction, as described in
  2112.    Section 13.2.1, "Extending Signed Values."
  2113.  
  2114.    By far the most common use of WORD PTR is in operations on objects 32 bits
  2115.    or longer. An 8086 instruction can operate only on a byte or a word. You
  2116.    use WORD PTR to tell the assembler to operate on one word at a time. For
  2117.    example, the following code uses two moves to copy the 32-bit integer X to
  2118.    a similar integer, Y:
  2119.  
  2120.    X     DD      80000               ; X is a long integer = 80,000
  2121.    Y     DD      ?                   ; Y is a long integer
  2122.          .
  2123.          .
  2124.          .
  2125.          mov     ax, WORD PTR X      ; Move word at X to word at Y
  2126.          mov     WORD PTR Y, ax      ;   (using AX as intermediate register)
  2127.          mov     ax, WORD PTR X[2]   ; Move word 2 bytes past X to
  2128.          mov     WORD PTR Y[2], ax   ;   word 2 bytes past Y
  2129.  
  2130.    Brackets ([ ]) are used with arrays as well as portions of large data
  2131.    objects as shown here; they also let you add a displacement to an address.
  2132.    The use of brackets is further explained in the next few paragraphs.
  2133.  
  2134.    Assembly language makes almost no distinction between simple variables and
  2135.    arrays. You refer to the first element of an array just as you would a
  2136.    simple variable──index brackets are optional. To declare an array or
  2137.    string, just give a series of initial values:
  2138.  
  2139.    warray      DW      ?,?,?,?
  2140.    xarray      DW      1,2,3,4
  2141.    mystring    DB      "Hello, there."
  2142.  
  2143.    To refer to the first element of warray, type warray into your program (no
  2144.    brackets required). To refer to the next element, use either of these two
  2145.    forms, each of which refers to the object two bytes past the beginning of
  2146.    warray:
  2147.  
  2148.    warray+2
  2149.    warray[2]
  2150.  
  2151.    When used with a variable name, the brackets do nothing but add a number
  2152.    to the address. If warray refers to the address 2400h, then warray[2]
  2153.    refers to the address 2402h. However, the brackets have an additional
  2154.    function when used with registers. See Section 2.6.4, "Indirect Memory
  2155.    Operands," for more information.
  2156.  
  2157.    In assembly language, array indexes are zero-based, as in C; but unlike C,
  2158.    they are unscaled. The number inside brackets always represents an
  2159.    absolute distance in bytes.
  2160.  
  2161.    In practical terms, the fact that indexes are unscaled means that if the
  2162.    size of an element is larger than one byte, you must multiply the index of
  2163.    the element by its size (in this case, 2), then add the result to the
  2164.    address of the array. Thus, the expression warray[4] represents the third
  2165.    element, which is 4 bytes past the beginning of the array. Similarly, the
  2166.    expression warray[6] represents the fourth element.
  2167.  
  2168.    In general, the numeric offset required to access an array element can be
  2169.    calculated as shown in the following formula:
  2170.  
  2171.    Nth element of Array = Array[(N-1) * size of element]
  2172.  
  2173.  
  2174.  2.5  8086-Family Registers
  2175.  
  2176.    A "register" is a special memory location inside the processor itself.
  2177.    Operations on registers execute faster than operations on main memory. The
  2178.    processor has a limited number of registers. Moreover, many operations on
  2179.    the 8086 are impossible without the use of registers at some point. For
  2180.    example, you cannot copy data between two memory locations without first
  2181.    moving it into a register.
  2182.  
  2183.    Figure 2.1 shows the registers common to all the 8086-family processors.
  2184.    The 8086 registers can be grouped by function into the following sets:
  2185.    general-purpose registers, index registers, pointer registers, and segment
  2186.    registers. Each set corresponds to a different ending letter (X, I, P, or
  2187.    S). The registers in each set are as follows:
  2188.  
  2189.    ┌────────────────────────────────────────────────────────────────────────┐
  2190.    │ This figure can be found in Section 2.5 of the manual                  │
  2191.    └────────────────────────────────────────────────────────────────────────┘
  2192.  
  2193.    ■  The four general-purpose registers are AX, BX, CX, and DX. These
  2194.       registers exist for the general use of the program. You can use these
  2195.       registers to store temporary values and perform calculations.
  2196.  
  2197.    ■  The two index registers are SI (Source Index) and DI (Destination
  2198.       Index). These registers can also be used for general storage, but are
  2199.       less flexible than the general-purpose registers. SI and DI have a
  2200.       special purpose in string instructions.
  2201.  
  2202.    ■  The pointer registers are IP (Instruction Pointer), SP (Stack Pointer),
  2203.       and BP (Base Pointer). These registers should not be confused with BX,
  2204.       which is the register normally used for pointer indirection. IP, SP,
  2205.       and BP each have a special purpose in conjunction with procedure calls.
  2206.       SP and BP should be altered with care; IP cannot be altered or
  2207.       referenced directly at all.
  2208.  
  2209.    ■  The segment registers are CS, DS, SS, and ES. This section does not
  2210.       describe these registers. You generally don't alter or reference them
  2211.       except when starting the program or accessing data from multiple
  2212.       segments. Section 2.7, "Segmented Addressing and Segment Registers,"
  2213.       describes each segment register and how it is important to programs.
  2214.  
  2215.    In addition, there is a flags register that indicates the status of the
  2216.    process.
  2217.  
  2218.  
  2219.  2.5.1  The General-Purpose Registers
  2220.  
  2221.    The general-purpose registers have many important uses in an 8086
  2222.    assembly-language program, including:
  2223.  
  2224.    ■  Storing the values most frequently used. Operations on registers are
  2225.       much faster than operations on memory. Therefore, place the program's
  2226.       principal values in registers. In larger programs, you will probably
  2227.       have too many variables to place them all into registers. You can,
  2228.       however, place a value in a register while it is in heavy use.
  2229.  
  2230.    ■  Supporting operations with two or more variables. Direct
  2231.       memory-to-memory operations are illegal with 8086 processors. To
  2232.       operate on two memory locations, you need to first load one of the
  2233.       values into a register.
  2234.  
  2235.    ■  Enabling use of all the instructions. Many instructions require the use
  2236.       of a particular register. For example, the MUL instruction always works
  2237.       with the AX register (or AL, if you specify a byte operand).
  2238.  
  2239.    ■  Passing or returning values in a procedure or interrupt call.
  2240.  
  2241.    Each of the general-purpose registers──AX, BX, CX, and DX──can be accessed
  2242.    as single 16-bit registers, or as two 8-bit registers. As shown in Figure
  2243.    2.1, the AH, BH, CH, and DH registers represent the high-order 8 bits of
  2244.    the corresponding registers. Similarly, AL, BL, CL, and DL represent the
  2245.    low-order 8 bits.
  2246.  
  2247.    This design lets you operate directly on two-byte and one-byte objects. It
  2248.    also lets you load a two-byte object and then manipulate one byte at a
  2249.    time.
  2250.  
  2251.    Each of the general-purpose registers has special uses, discussed below.
  2252.  
  2253.  
  2254.  2.5.1.1  The AX Register
  2255.  
  2256.    The AX (Accumulator) register is ideal for repeated calculations. It
  2257.    accumulates totals as well as the results of multiplication and division.
  2258.    Using AX can add speed to your program, because some instructions have
  2259.    special encodings optimized for use with AX.
  2260.  
  2261.    Multiplication instructions always use AX. In the 16-bit version of the
  2262.    MUL instruction, you specify one 16-bit value. The processor multiplies
  2263.    this value by the contents of AX and stores the 16 least significant
  2264.    binary digits of the result in AX. (The 16 most significant digits are
  2265.    stored in DX.)
  2266.  
  2267.    The following example multiplies base times height, and stores the result
  2268.    in area. These instructions are sufficient if the result does not exceed
  2269.    the limit for two-byte numbers (otherwise, the DX register will contain
  2270.    the overflow):
  2271.  
  2272.    base     DW     5       ; base is a word, initialized to 5
  2273.    height   DW     3       ; height is a word, initialized to 3
  2274.    area     DW     ?       ; area stores 16-bit (word) product
  2275.             .
  2276.             .
  2277.             .
  2278.             mov    ax,base ; AX = base
  2279.             mul    height  ; AX = AX * height
  2280.             mov    area,ax ; area = result
  2281.  
  2282.    AX has a similar use in division instructions (DIV and IDIV). See Section
  2283.    14.4, "Dividing," for examples of division. Also, in port I/O
  2284.    instructions, AX holds the data to write to a port and receives data read
  2285.    from a port.
  2286.  
  2287.    By convention, AX has another special use. Microsoft high-level languages
  2288.    expect AX to contain a function's return value. If the return value is
  2289.    longer than four bytes, the high-level languages expect DX:AX to point to
  2290.    the location of the return value.
  2291.  
  2292.  
  2293.  2.5.1.2  The BX Register
  2294.  
  2295.    The BX (Base) register has great importance as a pointer or address
  2296.    register. All 16-bit registers can hold addresses, but not all registers
  2297.    can be used to retrieve the contents of an address. In C this operation is
  2298.    called "pointer dereferencing," or "indirection." The C source code to
  2299.    implement this action might look like this:
  2300.  
  2301.    value = *pVar;
  2302.  
  2303.    The following assembly code achieves the same effect:
  2304.  
  2305.                mov     bx,pVar      ; BX = pVar
  2306.                mov     value,[bx]   ; value = object pointed to by BX
  2307.  
  2308.    The brackets around BX in the second instruction direct QuickAssembler to
  2309.    consider BX a pointer to the actual operand. The item [bx] is an example
  2310.    of an indirect memory operand. See Section 2.6.4, "Indirect Memory
  2311.    Operands," for more information.
  2312.  
  2313.  
  2314.  2.5.1.3  The CX Register
  2315.  
  2316.    The CX (Count) register has special meaning to instructions with a
  2317.    repeat-operation feature. The contents of CX indicate how many times to
  2318.    repeat execution. Loops, string operations, certain jump instructions, and
  2319.    shifts and rotates all use CX this way.
  2320.  
  2321.    A common instruction that uses CX to repeat execution is LOOP, which is
  2322.    analogous to the C for statement. This instruction subtracts one from CX,
  2323.    then jumps to the given label if CX is not equal to 0. Thus, the following
  2324.    loop executes 20 times:
  2325.  
  2326.                mov     cx,20
  2327.    top:
  2328.                .
  2329.                .
  2330.                .
  2331.                loop    top
  2332.  
  2333.    In the case of shifts and rotates, CL (the lower byte of CX) indicates how
  2334.    many bit positions to shift. See Section 14.7, "Shifting and Rotating
  2335.    Bits," for more information. Also, when an instruction has a REP (repeat)
  2336.    prefix, the value in CX determines how many times the instruction is
  2337.    executed.
  2338.  
  2339.  
  2340.  2.5.1.4  The DX Register
  2341.  
  2342.    The DX (Data) register often is used only for storage of temporary values.
  2343.    However, DX has a special function in some versions of the multiplication,
  2344.    division, and port instructions. Each of these uses is closely related to
  2345.    AX. In fact, DX is located next to AX in the actual physical layout of the
  2346.    8086 chip. (Figure 2.1 places the registers in the order AX, BX, CX, and
  2347.    DX merely for ease of reference.)
  2348.  
  2349.    When you multiply 16-bit values with MUL, DX holds the high 16 bits of the
  2350.    32-bit result. The following example is a variation of the one given for
  2351.    AX. In this example, Area is a 32-bit value (a long integer), and it
  2352.    stores the entire 32-bit result of the MUL instruction:
  2353.  
  2354.    base        DW     500                 ; base is a word, initialized to 500
  2355.    height      DW     300                 ; height is a word, initialized to 3
  2356.    area        DD     ?                   ; area stores doubleword product
  2357.                .
  2358.                .
  2359.                .
  2360.                mov    ax,base             ; AX = base
  2361.                mul    height              ; DX:AX = AX * height
  2362.                mov    WORD PTR area[0],ax ; Store low 16 bits
  2363.                mov    WORD PTR area[2],dx ; Store high 16 bits
  2364.  
  2365.    By convention, Microsoft high-level languages use both DX and AX to return
  2366.    four-byte values from procedures. The high 16 bits are placed in DX.
  2367.  
  2368.  
  2369.  2.5.2  The Index Registers
  2370.  
  2371.    The two index registers are SI (Source Index) and DI (Destination Index).
  2372.    These registers are similar to the general-purpose registers, but cannot
  2373.    be accessed one byte at a time. Index registers are efficient places to
  2374.    store general data, pointers, array indexes, and pointers to blocks of
  2375.    memory. They have the following special uses:
  2376.  
  2377.    ■  You can use both SI and DI for pointer indirection, as you can BX and
  2378.       BP. "Pointer indirection" is the process of retrieving the value that a
  2379.       pointer points to.
  2380.  
  2381.    ■  You can use SI or DI to hold an array index. Indirect memory operands
  2382.       can combine this index with a base address stored in BX or BP.
  2383.  
  2384.    ■  You prepare for string instructions, which execute highly efficient
  2385.       block operations, by loading SI with a source address and DI with a
  2386.       destination address.
  2387.  
  2388.    See Chapter 16, "Processing Strings," for information on how to use
  2389.    string instructions.
  2390.  
  2391.    When you write a procedure to be called by C, be careful to leave SI and
  2392.    DI in the same state they were in before C called your procedure.
  2393.    Microsoft QuickC allocates register variables in SI and DI.
  2394.  
  2395.  
  2396.  2.5.3  The Pointer Registers
  2397.  
  2398.    The pointer registers──BP, SP, and IP──are all special-purpose registers
  2399.    that help implement procedure calls. The processor alters SP (Stack
  2400.    Pointer) and IP (Instruction Pointer) whenever you call a procedure, and
  2401.    you can use BP (Base Pointer) to access parameters placed on the stack.
  2402.  
  2403.    Despite their names, pointer registers are not good places to store
  2404.    pointer variables or other general program data; you should generally use
  2405.    BX, SI, and DI for that purpose.
  2406.  
  2407.  
  2408.  2.5.3.1  The BP Register
  2409.  
  2410.    You can use BP (Base Pointer) to retrieve the contents pointed to by an
  2411.    address. However, by default, the BP register points into the stack
  2412.    segment rather than the data segment. Therefore, BP is typically used to
  2413.    access items on the stack.
  2414.  
  2415.    The "stack" is the area of memory that holds parameters, local variables,
  2416.    and return addresses for each procedure being executed. Although you can
  2417.    store general data in BP, it is commonly used to access parameters of the
  2418.    current procedure.
  2419.  
  2420.    When you use the PROC statement with a parameter list as explained in the
  2421.    next chapter, avoid altering the value of BP. The PROC directive generates
  2422.    instructions that set BP to point to the procedure's local stack area, and
  2423.    then use BP to access parameters and local data. If BP changes, all your
  2424.    references to parameters will be wrong.
  2425.  
  2426.    To learn how to set BP yourself, see Section 15.3.3, "Passing Arguments
  2427.    on the Stack," or Appendix A, "Mixed-Language Mechanics."
  2428.  
  2429.  
  2430.  2.5.3.2  The SP Register
  2431.  
  2432.    The SP (Stack Pointer) register points to the current location within the
  2433.    stack segment. As you add or remove items from the stack, the processor
  2434.    changes the value of SP, so that SP always points to the top of the stack.
  2435.  
  2436.    The processor stack works like a stack of dishes: you push items onto the
  2437.    top of the stack as you need to save them, then pop them off the stack
  2438.    when you're ready to use them again. The stack is a last-in-first-out
  2439.    mechanism. You can only remove the item currently at the top of the stack.
  2440.    Items must be removed in the reverse order they were placed there.
  2441.  
  2442.    The processor automatically pushes and pops return addresses for you when
  2443.    you call or return from a procedure. A "return address" is the place a
  2444.    procedure or routine returns to when done. You can also place other values
  2445.    on the stack by using the PUSH and POP instructions.
  2446.  
  2447.    The PUSH instruction saves the value of a register or memory location by
  2448.    placing it on the stack. POP removes the value from the stack and places
  2449.    it back in the original location. (You can also pop the contents into some
  2450.    other location if you wish.) Use these instructions when you need to
  2451.    preserve a value. In the following example, BX holds an important value,
  2452.    but the program needs temporary use of BX:
  2453.  
  2454.                push    bx             ; Save BX on the stack
  2455.                mov     bx,pointer     ; Load pointer into BX
  2456.                mov     value,[bx]     ; value = *pointer
  2457.                pop     bx             ; Pop old value back into BX
  2458.  
  2459.    The stack also holds parameters and local variables during procedure
  2460.    calls. Sections 13.4.2, "Using the Stack," and 15.3.3, "Passing
  2461.    Arguments on the Stack," provide more information on using the stack.
  2462.    Appendix A, "Mixed-Language Mechanics," explains how to manipulate the
  2463.    stack to make room for local variables──one of the few times you should
  2464.    change the value of SP directly.
  2465.  
  2466.  
  2467.  2.5.3.3  The IP Register
  2468.  
  2469.    You cannot adjust the IP (Instruction Pointer) register directly; it can
  2470.    only be adjusted indirectly, through control-flow instructions. For this
  2471.    reason, Quick-Assembler does not even recognize IP as a keyword.
  2472.  
  2473.    The IP register contains the address of the next instruction to execute.
  2474.    The instructions that control program flow (calls, jumps, loops, and
  2475.    interrupts) automatically set the instruction pointer to the proper value.
  2476.    The processor pushes the address of the next instruction onto the stack
  2477.    when you call a procedure. The processor pops this instruction into IP
  2478.    when the procedure returns. Normally, the processor increments IP to point
  2479.    to the next instruction in memory.
  2480.  
  2481.  
  2482.  2.5.4  The Flags Register
  2483.  
  2484.    The flags register, shown in Figure 2.2, is a 16-bit register made up of
  2485.    bits that each indicate some specific condition. Most of the flags help
  2486.    determine the behavior of conditional jump instructions. Many
  2487.    instructions──most notably CMP──set these flags in a meaningful way. Other
  2488.    flags (Trap, Interrupt Enable, and Direction) do not affect conditional
  2489.    jump instructions but control the processor's general operation.
  2490.  
  2491.    ┌────────────────────────────────────────────────────────────────────────┐
  2492.    │ This figure can be found in Section 2.5.4 of the manual                │
  2493.    └────────────────────────────────────────────────────────────────────────┘
  2494.  
  2495.    The nine flags common to all 8086-family processors are summarized below,
  2496.    progressing from the low-order to high-order flags. In these descriptions,
  2497.    the term "set" means the bit value is 1, and "cleared" means the bit value
  2498.    is 0.
  2499.  
  2500.    Instructions actively set and clear various flags. For example, if the
  2501.    result of a SUB or CMP instruction is zero, it sets the Zero flag. This
  2502.    flag setting can, in turn, affect subsequent instructions──in particular,
  2503.    conditional jumps. Some instructions do not set the flags at all, or have
  2504.    random effects on some flags. Consult on-line Help for each instruction to
  2505.    see precisely how it affects flag settings.
  2506.  
  2507.    Flag                Description
  2508.    ──────────────────────────────────────────────────────────────────────────
  2509.    Carry               Is set if an operation generates a carry to or a
  2510.                        borrow from a destination operand. (Operation viewed
  2511.                        as unsigned.)
  2512.  
  2513.    Parity              Is set if the low-order bits of the result of an
  2514.                        operation contain an even number of set bits.
  2515.  
  2516.    Auxiliary Carry     Is set if an operation generates a carry to or a
  2517.                        borrow from the low-order four bits of an operand.
  2518.                        This flag is used for binary coded decimal arithmetic.
  2519.  
  2520.    Zero                Is set if the result of an operation is 0.
  2521.  
  2522.    Sign                Equal to the high-order bit of the result of an
  2523.                        operation (0 is positive, 1 is negative).
  2524.  
  2525.    Trap                If set, the processor generates a single-step
  2526.                        interrupt after each instruction. Debugging programs,
  2527.                        including the QuickC/QuickAssembler debugging
  2528.                        facility, use this feature to execute a program one
  2529.                        instruction at a time.
  2530.  
  2531.    Interrupt Enable    If set, interrupts will be recognized and acted on as
  2532.                        they are received. The bit can be cleared to
  2533.                        temporarily turn off interrupt processing.
  2534.  
  2535.    Direction           Can be set to make string operations process down from
  2536.                        high addresses to low addresses, or can be cleared to
  2537.                        make string operations process up from low addresses
  2538.                        to high addresses.
  2539.  
  2540.    Overflow            Is set if the result of an operation is too large or
  2541.                        small to fit in the destination operand. (Operation
  2542.                        viewed as signed.)
  2543.  
  2544.  
  2545.    The Carry and Overflow flags are similar, but have one major difference:
  2546.    the Carry flag is set according to the rules of unsigned operations, and
  2547.    the Overflow flag is set according to the rules of signed operations. A
  2548.    signed operation uses two's complement arithmetic to represent negative
  2549.    numbers. One of the features of this system is that a number is negative
  2550.    if the most significant bit is set. Unsigned operations do not view any
  2551.    number as negative.
  2552.  
  2553.    Thus, the same ADD operation can be viewed as adding FFFFH to FFFEH
  2554.    (unsigned) or -1 to -2 (signed). This operation would set the Carry flag
  2555.    (because the maximum unsigned value is FFFFH), but not the Overflow flag.
  2556.  
  2557.    ──────────────────────────────────────────────────────────────────────────
  2558.    NOTE  This manual does not describe the details of two's-complement
  2559.    arithmetic. For more information, see one of the references listed in the
  2560.    Introduction.
  2561.    ──────────────────────────────────────────────────────────────────────────
  2562.  
  2563.    Each of the conditional jump instructions responds to a particular flag or
  2564.    combination of flags. For example, the JZ (Jump If Zero) instruction jumps
  2565.    if the Zero flag is set. The JBE (Jump If Below or Equal) jumps if either
  2566.    the Zero flag or the Carry flag is set. For a description of all the
  2567.    conditional jump instructions, see Section 15.1.2, "Jumping
  2568.    Conditionally."
  2569.  
  2570.  
  2571.  2.6  Addressing Modes
  2572.  
  2573.    You can specify several kinds of operands: immediate, register, direct
  2574.    memory, and indirect memory. Each type of operand corresponds to a
  2575.    different addressing mode. The "addressing mode" is the method that the
  2576.    processor uses to calculate the actual value of the operand at run time.
  2577.  
  2578.    You don't specify addressing modes explicitly. You simply give an operand,
  2579.    and the assembler determines the corresponding addressing mode.
  2580.  
  2581.    The four types of operands are summarized below, and described at length
  2582.    in the rest of this section.
  2583.  
  2584.    Operand Type        Description
  2585.    ──────────────────────────────────────────────────────────────────────────
  2586.    Immediate           A constant value contained in the instruction itself
  2587.  
  2588.    Register            A 16-bit or 8-bit register
  2589.  
  2590.    Direct memory       A fixed location in memory
  2591.  
  2592.    Indirect memory     A memory location determined at run time by using the
  2593.                        address stored in one or two registers
  2594.  
  2595.  
  2596.    Direct memory and indirect memory operands are closely related. Syntax
  2597.    displays in this manual, as well as in on-line Help, often refer to memory
  2598.    operands. You can use either type of memory operand wherever memory is
  2599.    specified. From the processor's viewpoint, the only difference between
  2600.    these types of operands is how the address is determined. The address
  2601.    specified in the memory operand is called the "effective address" of the
  2602.    instruction.
  2603.  
  2604.    Most two-operand instructions require operands of the same size. When one
  2605.    of the operands is a register, QuickAssembler adjusts the size of the
  2606.    other, if possible, to be the size of the register──either 8 or 16 bits.
  2607.    An instruction that operates on AX and BL is illegal, since these
  2608.    registers are different sizes.
  2609.  
  2610.    If the sizes conflict, you can sometimes use the PTR operator to override
  2611.    the size attribute of an operand.
  2612.  
  2613.    Sections 2.6.1-2.6.4 discuss each of the four operand types (and
  2614.    corresponding addressing modes) in detail.
  2615.  
  2616.  
  2617.  2.6.1  Immediate Operands
  2618.  
  2619.    An "immediate operand" is a constant value on which the instruction
  2620.    operates directly. This is the only addressing mode that involves no
  2621.    further access of registers or memory. The data follows the instruction
  2622.    right inside the executable code, thus giving rise to the name
  2623.    "immediate."
  2624.  
  2625.    Use immediate operands for the same reasons you would use a literal or
  2626.    symbolic constant in C. The value of an immediate operand never changes.
  2627.  
  2628.    An immediate operand can be a symbolic constant declared with the EQU
  2629.    operand. This operand is often used for the same purpose as the C #define
  2630.    directive. For example, consider the constant declaration:
  2631.  
  2632.    magic       EQU     7243
  2633.  
  2634.    You could use this the same way as the C statement:
  2635.  
  2636.    #define magic  7243
  2637.  
  2638.    Chapter 11, "Using Equates, Macros, and Repeat Blocks," tells more about
  2639.    defining constants with the EQU or = operator.
  2640.  
  2641.    An immediate operand can also be an expression made up of constants. For
  2642.    example, the following code directs QuickAssembler to calculate the
  2643.    difference between two ASCII values, then use this difference as the
  2644.    source (rightmost) operand:
  2645.  
  2646.                mov     bigdiff,'a'-'A'
  2647.  
  2648.    The assembler interprets the one-byte strings 'a' and 'A' as the ASCII
  2649.    values 97 and 65. The assembler calculates the difference──in this case,
  2650.    32──and places the resulting value into the object code. At run time, this
  2651.    value is fixed. Each time the instruction is executed, the processor moves
  2652.    the value 32 into the memory location bigdiff. This instruction is
  2653.    precisely equivalent to, but more readable than, the following:
  2654.  
  2655.                mov     bigdiff,32
  2656.  
  2657.    One-byte and two-byte strings can be immediate operands. Larger strings
  2658.    cannot be processed by a single 8086 instruction. Chapter 3, "Writing
  2659.    Assembly Modules for C Programs," explains how to process longer strings,
  2660.    one character at a time.
  2661.  
  2662.    The OFFSET and SEG operators turn variable names (which normally are
  2663.    memory operands) into immediate operands. These operators are similar to
  2664.    the address operator (&) in C. In Chapter 4, "Writing Stand-Alone
  2665.    Assembly Programs," you'll see how to use the OFFSET operator to treat an
  2666.    address as immediate data.
  2667.  
  2668.    When an instruction has two operands, you cannot place immediate data in
  2669.    the destination (leftmost) operand. (The OUT instruction is the one
  2670.    exception.)
  2671.  
  2672.    Examples
  2673.  
  2674.    var         DW        ?
  2675.    college     DW        1636
  2676.    nine        EQU       5+4           ; Declare nine as symbolic constant
  2677.                .
  2678.                .
  2679.                .
  2680.                mov       var,nine      ; Move immediate data to memory
  2681.                mov       bx,'ab'       ; Move ASCII values for 'a' and 'b'
  2682.                                        ;   into BH and BL
  2683.                mov       college,1701  ; Move immediate data to memory
  2684.                mov       ax,1+2+3+4    ; Move immediate data to AX
  2685.                mov       ax,OFFSET var ; Move address of var to AX
  2686.                int       21h           ; Immediate data is single operand
  2687.                                        ;   21 hexadecimal (33 decimal)
  2688.  
  2689.  
  2690.  2.6.2  Register Operands
  2691.  
  2692.    A register operand consists of one of the 20 register names. The processor
  2693.    operates directly on the data stored in the register. "Register-direct"
  2694.    mode refers to the direct use of the value of the register rather than a
  2695.    memory location. Registers can also be used indirectly, to point to memory
  2696.    locations as described in Section 2.6.4, "Indirect Memory Operands."
  2697.  
  2698.    Most instructions can take one or more register operands. You generally
  2699.    can use any of the general-purpose registers with these instructions,
  2700.    although some instructions require specific registers. The use of segment
  2701.    registers (CS, DS, SS, and ES) is restricted. You can refer to segment
  2702.    registers only under special circumstances.
  2703.  
  2704.    Table 2.1 shows all the valid register names for 8086 processors. You can
  2705.    use any of these names as a register-direct operand.
  2706.  
  2707.    Table 2.1 Register Operands
  2708.  
  2709.    Register Type         Register
  2710.                          Name
  2711.    ──────────────────────────────────────────────────────────────────────────
  2712.    8-bit high registers  AH          BH          CH          DH
  2713.  
  2714.    8-bit low registers   AL          BL          CL          DL
  2715.  
  2716.    16-bit general        AX          BX          CX          DX
  2717.    purpose
  2718.    16-bit pointer and    SP          BP          SI          DI
  2719.    index
  2720.    16-bit segment        CS          DS          SS          ES
  2721.  
  2722.    ──────────────────────────────────────────────────────────────────────────
  2723.  
  2724.  
  2725.    Section 2.5, "8086-Family Registers," discusses registers in more detail.
  2726.    Limitations on register use for specific instructions are discussed in
  2727.    sections on the specific instructions throughout Part 3, "Using
  2728.    Instructions."
  2729.  
  2730.    Examples
  2731.  
  2732.           mov         ds,ax         ; Both operands are register direct
  2733.           mov         stuff,dx      ; Source operand is register direct
  2734.           mov         ax,1          ; Destination is register direct
  2735.           mul         bx            ; Single operand, register direct
  2736.  
  2737.  
  2738.  2.6.3  Direct Memory Operands
  2739.  
  2740.    A direct memory operand specifies a fixed address in main memory
  2741.    containing the data to operate on. At the machine level, a direct memory
  2742.    operand is a numeric address. In your QuickAssembler source code, you
  2743.    usually represent a direct memory operand by entering a symbolic name
  2744.    previously declared with a data directive such as DB (Declare Bytes).
  2745.  
  2746.    A direct memory operand is similar to a simple variable in C or an array
  2747.    element with a constant index. Any object in memory can be a direct memory
  2748.    operand as long as the exact location is fixed in the executable code. The
  2749.    data at the location can change, but the location itself is the same each
  2750.    time the processor executes the instruction. This fact gives direct memory
  2751.    operands a static character. For more dynamic operations, use indirect
  2752.    memory operands.
  2753.  
  2754.    Examples
  2755.  
  2756.                mov     ax,count    ; Source operand is direct memory
  2757.                mov     count,ax    ; Destination operand is direct memory
  2758.                inc     total       ; Single operand is direct memory
  2759.  
  2760.    Typically, a direct memory operand is a simple label. As with immediate
  2761.    operands, you can specify a direct memory operand by entering an
  2762.    expression. As long as the address can be determined at assembly time, the
  2763.    operand is direct memory.
  2764.  
  2765.    ──────────────────────────────────────────────────────────────────────────
  2766.    NOTE  Technically, a program address is not determined until link time (in
  2767.    the case of near addresses) or load time (in the case of segment
  2768.    addresses). These adjustments are necessary to support multiple modules
  2769.    and to enable the program to run anywhere in memory. However, you can
  2770.    ignore these details. If the assembler can determine the operand's address
  2771.    relative to the rest of the module, the operand is direct memory.
  2772.    ──────────────────────────────────────────────────────────────────────────
  2773.  
  2774.    The following example uses an expression that translates to a direct
  2775.    memory operand. This example could be used to load the value of DX into
  2776.    the third element of an array of bytes. QuickAssembler considers area[2]
  2777.    as equivalent to area+2.
  2778.  
  2779.                mov   area[2],dx   ; Move DX to memory location 2 bytes
  2780.                                   ;   past the address of "area"
  2781.  
  2782.    In the statement above, the assembler calculates an address by adding 2 to
  2783.    the address of area. The resulting address will be the same no matter what
  2784.    values are stored in registers. At run time, the address is fixed. Thus,
  2785.    the operand is direct memory.
  2786.  
  2787.    You can use a numeric constant as a direct memory operand. Normally,
  2788.    Quick-Assembler interprets a numeric constant as an immediate operand. To
  2789.    ensure interpretation as a memory operand, prefix the number with a
  2790.    segment register and colon (:). Brackets are optional. The following
  2791.    instructions each load AX with the contents of memory address 100
  2792.    hexadecimal in the data segment:
  2793.  
  2794.                mov     ax,ds:[100h]
  2795.                mov     ax,ds:100h
  2796.  
  2797.    Section 2.7, "Segmented Addressing and Segment Registers," provides more
  2798.    information on segment registers and the use of the colon (:). By default,
  2799.    the processor assumes that data references lie in the segment pointed to
  2800.    by DS.
  2801.  
  2802.  
  2803.  2.6.4  Indirect Memory Operands
  2804.  
  2805.    With indirect memory operands, the processor calculates the address of the
  2806.    data at execution time, by referring to the contents of one or two
  2807.    registers. Since values in the registers can change at run time, indirect
  2808.    memory operands provide the most dynamic method for accessing data.
  2809.  
  2810.    Indirect memory operands make possible run-time operations such as pointer
  2811.    indirection, dynamic indexing of array elements──including indexing of
  2812.    multi-dimensional arrays──and dynamic accessing of members of a structure.
  2813.    All these operations are similar to operations in high-level languages.
  2814.    The major difference is that assembly language requires you to use one of
  2815.    several specific registers: BX, BP, SI, and DI.
  2816.  
  2817.    You indicate an indirect memory operand by using at least one pair of
  2818.    brackets. Use of the index operator ([ ]) is explained in more detail in
  2819.    Section 9.2.1.3.
  2820.  
  2821.    When you place a register name in brackets, the processor uses the data
  2822.    pointed to by the register. For example, the following instruction
  2823.    accesses the data at the address contained in BX, and then moves this data
  2824.    into AX:
  2825.  
  2826.                mov     ax,[bx]
  2827.  
  2828.    When you specify more than one register, the processor adds the contents
  2829.    together to determine the effective address (the address of the data to
  2830.    operate on). One register must be a base register (BX or BP), and the
  2831.    other must be an index register (SI or DI):
  2832.  
  2833.                mov     ax,[bx+si]
  2834.  
  2835.    You can specify one or more displacements. A "displacement" is a constant
  2836.    value to add to the effective address. A simple use of a displacement is
  2837.    to add a base address to a register:
  2838.  
  2839.                mov     ax,table[si]
  2840.  
  2841.    In the example above, the displacement table is the address of an array;
  2842.    SI holds an index to an array element. (Unlike C, an assembly-language
  2843.    index always indicates the distance in bytes between the beginning of the
  2844.    array and the element.) Each time the instruction executes, it may load a
  2845.    different element into AX. The value of SI determines which array element
  2846.    to load.
  2847.  
  2848.    Each displacement can be an address or numeric constant. If there is more
  2849.    than one displacement, the assembler adds them all together at assembly
  2850.    time, and places the total displacement into the executable code. For
  2851.    example, in the statement
  2852.  
  2853.                mov     ax,table[bx][di]+6
  2854.  
  2855.    both table and 6 are displacements. The assembler adds the value of table
  2856.    to 6 to get the total displacement.
  2857.  
  2858.    Table 2.2 shows the modes in which registers can be used to specify
  2859.    indirect memory operands.
  2860.  
  2861.    Table 2.2 Indirect Addressing Modes
  2862.  
  2863.    Mode                Syntax                  Description
  2864.    ──────────────────────────────────────────────────────────────────────────
  2865.    Register indirect   [BX] [BP] [DI] [DI]     Effective address is contents
  2866.                                                of register
  2867.  
  2868.    ──────────────────────────────────────────────────────────────────────────
  2869.    Based or indexed    displacement[BX]        Effective address is contents
  2870.                        displacement[BP]        of register plus displacement
  2871.                        displacement[DI]
  2872.                        displacement[SI]
  2873.    ──────────────────────────────────────────────────────────────────────────
  2874.    Based indexed       [BX][DI] [BP][DI]       Effective address is contents
  2875.                        [BX][SI] [BP][SI]       of base register plus contents
  2876.                                                of index register
  2877.  
  2878.    ──────────────────────────────────────────────────────────────────────────
  2879.    Based indexed with  displacement[BX][DI]    Effective address is the sum
  2880.    displacement        displacement[BP][DI]    of base register, index
  2881.                        displacement[BX][SI]    register, plus displacement
  2882.                        displacement[BP][SI]
  2883.    ──────────────────────────────────────────────────────────────────────────
  2884.  
  2885.  
  2886.    You can enclose each register in its own pair of brackets, or you can
  2887.    place the registers in the same pair of brackets separated by a plus sign
  2888.    (+). The period (.) is normally used with structures, but it also
  2889.    indicates addition. The following statements are equivalent:
  2890.  
  2891.                mov     ax,table[bx][di]
  2892.                mov     ax,table[bx+di]
  2893.                mov     ax,[table+bx+di]
  2894.                mov     ax,[bx][di].table
  2895.                mov     ax,[bx][di]+table
  2896.                mov     ax,table[di][bx]
  2897.  
  2898.  
  2899.  2.7  Segmented Addressing and Segment Registers
  2900.  
  2901.    "Segmented addressing" is the internal mechanism that enables the
  2902.    processor to address up to one megabyte of main memory. This mechanism
  2903.    accesses each physical memory location by combining two 16-bit addresses.
  2904.    The two addresses can be represented in source code as follows:
  2905.  
  2906.    segment:offset
  2907.  
  2908.    The first 16-bit address is the "segment address." The second 16-bit
  2909.    address is the "offset address." In effect, the segment address selects a
  2910.    64K region of memory, and the offset address selects a byte within this
  2911.    region. Here's how it works:
  2912.  
  2913.    1. The processor shifts the segment address left by four places, producing
  2914.       a 20-bit address ending in four zeros. This operation has the effect of
  2915.       multiplying the segment address by 16.
  2916.  
  2917.    2. The processor adds this 20-bit address to the 16-bit offset address.
  2918.       The offset address is not shifted.
  2919.  
  2920.    3. The processor uses the resulting 20-bit address, often called the
  2921.       "physical address," to access an actual location in the one-megabyte
  2922.       address space.
  2923.  
  2924.    Figure 2.3 illustrates this process. The 8086-family processors were
  2925.    developed to use this mechanism because 16 bits (the size of an 8086
  2926.    register) can only address 64K at a time. However, the combined 20-bit
  2927.    address is sufficient to address a full megabyte. Note that DOS and ROM
  2928.    BIOS reserve part of this area, so that no more than 640K is available for
  2929.    program addresses.
  2930.  
  2931.    ┌────────────────────────────────────────────────────────────────────────┐
  2932.    │ This figure can be found in Section 2.7 of the manual                  │
  2933.    └────────────────────────────────────────────────────────────────────────┘
  2934.  
  2935.    A "segment" consists of a series of addresses that share the same segment
  2936.    address, but different offsets. Segments can be no more than 64K in size.
  2937.    To create large programs, you need to divide your program into multiple
  2938.    segments. Even with smaller programs, it is convenient to have separate
  2939.    code, data, and stack segments. (With tiny-model programs, the linker
  2940.    combines these segments into a single physical segment.)
  2941.  
  2942.    The following example helps illustrate segmented-address calculations
  2943.    further. The processor calculates the address 53C2:107A by multiplying the
  2944.    segment portion of the address by 16 (10H), and then adding the offset
  2945.    portion, as shown below:
  2946.  
  2947.        53C20h           Segment times 10h
  2948.  
  2949.     +   107Ah           Offset
  2950.  
  2951.        54C9Ah           Physical address
  2952.  
  2953.    The use of segmented architecture doesn't mean that you have to specify
  2954.    two addresses every time you access memory. The 8086-family processors use
  2955.    four segment registers, which simplify programming in the following ways:
  2956.  
  2957.    ■  Normally, you don't specify a segment address when you access data.
  2958.       Every data reference is relative to one of the four segment
  2959.       registers──CS, DS, SS, or ES──so the segment address is implied.
  2960.  
  2961.    ■  Most of the time, you don't need to tell the processor which segment
  2962.       register to use. By default, the processor uses CS for code addresses,
  2963.       DS for data addresses, and SS for stack addresses, except where
  2964.       otherwise noted in this section.
  2965.  
  2966.    ■  You initialize segment registers at the beginning of your program. Once
  2967.       initialized, you can continue to use the segment addresses stored in
  2968.       those registers.
  2969.  
  2970.    If the program uses medium, large, huge, or compact model, you may need to
  2971.    periodically reload one or more of the segment registers. These memory
  2972.    models let you use more than 64K of code or 64K of data.
  2973.  
  2974.    However, if the program uses small or tiny model, you never reload a
  2975.    segment register except in the following situations: to access a special
  2976.    hardware-defined location in memory, such as the video-display area, or to
  2977.    access far memory allocated to the program by DOS function 48H.
  2978.  
  2979.    Although each memory operand has a default segment register (usually DS,
  2980.    unless the operand uses BP), you can specify another segment register by
  2981.    using the segment override operator (:). The following example loads the
  2982.    variable far_away residing in the segment pointed to by ES:
  2983.  
  2984.                mov     ax,es:far_away
  2985.  
  2986.    For more information on this operator, see Section 9.2.3,
  2987.    "Segment-Override Operator."
  2988.  
  2989.    The CS Register
  2990.  
  2991.    The processor always uses the CS (Code Segment) register as the segment
  2992.    address of the next instruction to execute; IP (Instruction Pointer) holds
  2993.    the offset address. CS:IP represents the full address of the next
  2994.    instruction.
  2995.  
  2996.    Near jumps and procedure calls alter the value of IP. Far jumps and
  2997.    procedure calls alter both CS and IP. You never alter CS directly because
  2998.    the far jump and call instructions do so automatically. Furthermore, DOS
  2999.    initializes CS for you at the beginning of the program.
  3000.  
  3001.    The DS Register
  3002.  
  3003.    By default, the processor uses the DS (Data Segment) register as the
  3004.    segment address for program data. String instructions and indirect memory
  3005.    operands present some exceptions to this rule. With indirect memory
  3006.    operands, the use of BP anywhere in the operand causes SS to be the
  3007.    default segment register. Otherwise, DS is the default.
  3008.  
  3009.    All the Microsoft standard memory models place the most frequently used
  3010.    data in an area pointed to by DS. This area is commonly called the
  3011.    "default data area," and it can be no larger than 64K. These memory models
  3012.    use the ES register to access data outside the default data area. Your own
  3013.    programs can either use this technique, or else reload DS whenever you
  3014.    enter a new module. The standard method has the advantage of providing
  3015.    fast access to the most frequently used data.
  3016.  
  3017.    The SS Register
  3018.  
  3019.    When the processor accesses data on the stack, it uses the SS (Stack
  3020.    Segment) register as the segment register. (See the description of SP in
  3021.    Section 2.5.3 for more information about the stack.) Thus, SS:SP always
  3022.    points to the current stack position. Indirect memory operands involving
  3023.    BP also use SS as the default segment register.
  3024.  
  3025.    The Microsoft standard memory models set SS equal to DS. This setting
  3026.    makes some programming tasks easier. In particular, it lets you address
  3027.    stack or data addresses with either register. If you have to reload DS,
  3028.    you can always access items in the default data area by using an SS
  3029.    override.
  3030.  
  3031.    The ES Register
  3032.  
  3033.    The ES (Extra Segment) register is convenient for accessing data outside
  3034.    of the default data area. As demonstrated in Section 3.4, "Decimal
  3035.    Conversion with Far Data Pointers," you access far data by loading ES with
  3036.    the desired segment address, and then giving a segment override. Section
  3037.    13.3.2, "Loading Far Pointers," provides further information.
  3038.  
  3039.    ES also plays a role in string instructions. With these instructions, the
  3040.    DI (Destination Index) register is always relative to the segment address
  3041.    in ES.
  3042.  
  3043.  
  3044.  
  3045.  ────────────────────────────────────────────────────────────────────────────
  3046.  Chapter 3:  Writing Assembly Modules for C Programs
  3047.  
  3048.  
  3049.    As a C programmer, you can take advantage of the superior speed and
  3050.    compactness of assembly-language routines. You can write most of your
  3051.    program in C, then write time-critical routines in assembly language.
  3052.  
  3053.    This chapter presents QuickAssembler programming techniques for
  3054.    interfacing to C. You can use similar techniques to interface with other
  3055.    languages. By using C with assembly language, however, you gain the
  3056.    advantage of being able to develop the entire program from within the
  3057.    integrated environment.
  3058.  
  3059.    If you've read Chapter 2, read this chapter to see how to use assembly
  3060.    language in a complete example module. If you skipped over Chapter 2, you
  3061.    may want to refer to it occasionally for basic concepts, such as
  3062.    instructions and registers.
  3063.  
  3064.  
  3065.  3.1  A Skeleton for Procedure Modules
  3066.  
  3067.    Let's start by looking at the skeleton of a module with one procedure. The
  3068.    "skeleton" consists of statements that give basic structure to the module.
  3069.    Within this structure, you can supply most any instructions you want.
  3070.    Later sections of this chapter flesh out the skeleton by supplying useful
  3071.    code.
  3072.  
  3073.    The following skeleton assumes that the module is called by a small-model
  3074.    C program, and consists of one procedure which takes a single parameter, a
  3075.    pointer to a byte:
  3076.  
  3077.                .MODEL  small,c
  3078.                .CODE
  3079.  
  3080.    dectoint    PROC    Array:PTR BYTE
  3081.    ;
  3082.    ;   (supply executable code here)
  3083.    ;
  3084.    dectoint    ENDP
  3085.                END
  3086.  
  3087.    Some features of the skeleton change when you write different procedures.
  3088.    Other parts may remain the same. In particular, you'll need to add a PROC
  3089.    and ENDP statement each time you add another procedure to the module.
  3090.  
  3091.    Before looking at a full program example, let's examine each part of the
  3092.    skeleton.
  3093.  
  3094.  
  3095.  3.1.1  The .MODEL Directive
  3096.  
  3097.    The .MODEL directive gives general information about the module. It uses
  3098.    the following syntax:
  3099.  
  3100.    .MODEL memorymodel [[,langtype [[,stacktype]]]]
  3101.  
  3102.    The last two fields are optional. Commas are field separators and are only
  3103.    required if you use more than one field. Usually, you'll want to enter
  3104.    values in the first two fields.
  3105.  
  3106.    The memorymodel and langtype fields correspond to the memory model and
  3107.    language, respectively, of the calling module. If your C program declares
  3108.    your procedure to be of type pascal or fortran, use Pascal, BASIC, or
  3109.    FORTRAN in the langtype field. These keywords specify the use of the non-C
  3110.    calling and naming conventions. Otherwise, specify C as the langtype.
  3111.    Although the langtype field is optional, you should supply it since the
  3112.    PROC features described later in this chapter require it.
  3113.  
  3114.    Don't use the stacktype field unless the calling C program is compiled
  3115.    with SS not equal to DS, in which case you should type in farStack.
  3116.    (QuickC does not generate code that sets SS not equal to DS, but other
  3117.    versions of Microsoft C do support this option.) The default is nearStack,
  3118.    which assumes SS is equal to DS.
  3119.  
  3120.  
  3121.  3.1.2  The .CODE Directive
  3122.  
  3123.    The .CODE directive marks the beginning of the code segment, which is the
  3124.    section of your program that contains the actual steps to execute:
  3125.  
  3126.                .CODE
  3127.  
  3128.    Statements that follow this directive are considered part of the code
  3129.    segment. The segment continues to the end of the module or the next
  3130.    segment directive. Typically, the code segment consists of instructions
  3131.    and procedure definitions. It can also contain macro calls.
  3132.  
  3133.    Some procedures work with static data. In Chapter 4, "Writing Stand-Alone
  3134.    Assembly Programs," you'll see how to declare a data segment in which you
  3135.    can place data declarations.
  3136.  
  3137.  
  3138.  3.1.3  The PROC Directive
  3139.  
  3140.    Use the PROC directive to define a procedure. The name of the procedure
  3141.    appears in the first column:
  3142.  
  3143.    dectoint    PROC    Array:PTR BYTE
  3144.  
  3145.    Because the .MODEL statement specified C-language conventions, the
  3146.    assembler prefixes the name dectoint with an underscore (_), and places
  3147.    the name into object code as a public code label.
  3148.  
  3149.    If your procedure alters registers that should be preserved, the optional
  3150.    USES keyword automatically generates code to push the value of these
  3151.    registers on the stack and pop them when the procedure returns. Procedures
  3152.    called by C should not corrupt the value of SI, DI, or the segment
  3153.    registers CS, DS, or SS. (The value of BP is automatically preserved.) The
  3154.    following example shows how to preserve SI and DI for a procedure that
  3155.    changes these registers:
  3156.  
  3157.    dectoint    PROC    USES si di, Array:PTR BYTE
  3158.  
  3159.    The last part of the statement declares one or more parameters. In this
  3160.    case, the procedure declares a single parameter, Array, as a pointer to a
  3161.    byte. The most common parameter types you can declare are listed below:
  3162.  
  3163.    Declaration         Meaning
  3164.    ──────────────────────────────────────────────────────────────────────────
  3165.    WORD                Word (two bytes)
  3166.  
  3167.    DWORD               Doubleword (four bytes)
  3168.  
  3169.    PTR BYTE            Pointer to a byte; most commonly, a pointer to a
  3170.                        character string
  3171.  
  3172.    PTR WORD            Pointer to a word; typically, the address of an array
  3173.                        of integers
  3174.  
  3175.    PTR DWORD           Pointer to a doubleword
  3176.  
  3177.  
  3178.    For example, the following procedure definition declares a procedure named
  3179.    MidStr, which takes as parameters two pointers to character strings and
  3180.    one integer:
  3181.  
  3182.    MidStr      PROC    Str1:PTR BYTE, Str2:PTR BYTE, Index:WORD
  3183.  
  3184.    References to parameters are really references to locations on the stack.
  3185.    C modules pass parameters by pushing them on the stack just before calling
  3186.    the procedure. The BP register serves as a framepointer (a pointer to the
  3187.    procedure's stack area), and each parameter is an offset from BP. The
  3188.    exact offset of each parameter depends on the memory model and calling
  3189.    convention, both established by the .MODEL directive.
  3190.  
  3191.    When you use QuickAssembler procedure definitions, the assembler automates
  3192.    the work of referring to parameters. Instead of setting up the
  3193.    framepointer or calculating parameter offsets, you simply refer to
  3194.    parameters by name. You can also use these names with debugging commands.
  3195.  
  3196.    Appendix A, "Mixed-Language Mechanics," shows the actual code that
  3197.    establishes BP as the framepointer. It also shows how to calculate
  3198.    parameter offsets.
  3199.  
  3200.    Section 6.4.3, "Procedure Labels," gives the complete syntax and rules
  3201.    for using the PROC statement.
  3202.  
  3203.  
  3204.  3.1.4  The ENDP and END Statements
  3205.  
  3206.    The module ends with two statements: ENDP, which declares the end of a
  3207.    procedure, and END, which declares the end of the module:
  3208.  
  3209.    dectoint    ENDP
  3210.                END
  3211.  
  3212.    You can place any number of procedures in the same module. Each time you
  3213.    end a procedure, use ENDP. However, END should only occur once, at the end
  3214.    of the module.
  3215.  
  3216.  
  3217.  3.2  Instructions Used in This Chapter
  3218.  
  3219.    The instructions below were introduced in Chapter 2, "Introducing 8086
  3220.    Assembly Language." They are summarized here briefly for review. The first
  3221.    group of instructions manipulates data:
  3222.  
  3223.    Instruction               Description
  3224.    ──────────────────────────────────────────────────────────────────────────
  3225.    MOV destination, source   Copies value of source to destination
  3226.  
  3227.    ADD destination, source   Adds source to destination, storing result in
  3228.                              destination
  3229.  
  3230.    SUB destination, source   Subtracts source from destination, storing
  3231.                              result in destination
  3232.  
  3233.    INC destination           Increment──adds 1 to destination
  3234.  
  3235.    DEC destination           Decrement──subtracts 1 from destination
  3236.  
  3237.    MUL source                Multiplies source by AX (if operand is 16 bits),
  3238.                              storing high 16 bits in DX and low 16 bits in AX
  3239.  
  3240.  
  3241.    The second group of instructions controls the flow of program execution:
  3242.  
  3243.    Instruction         Description
  3244.    ──────────────────────────────────────────────────────────────────────────
  3245.    CMP destination,    Compare──subtracts source from destination, ignoring
  3246.    source              result but setting processor flags appropriately
  3247.  
  3248.    JE label            Jumps to label if result of last operation was equal
  3249.                        to zero
  3250.  
  3251.    JAE label           Jumps to label if result of last operation was equal
  3252.                        to or above zero (unsigned operations)
  3253.  
  3254.    JMP label           Jumps unconditionally to label
  3255.  
  3256.  
  3257.  
  3258.  3.3  Decimal Conversion Example
  3259.  
  3260.    This section uses a decimal-conversion example to illustrate the use of
  3261.    some basic instructions and directives. It features an assembly module
  3262.    that takes a pointer to a null-terminated string of characters as input
  3263.    and returns an unsigned integer value. This chapter assumes that the value
  3264.    is unsigned.
  3265.  
  3266.    You can compute the value of a decimal string by multiplying each digit by
  3267.    a power of 10:
  3268.  
  3269.    2035 = 2 x 10 cubed + 0 x 10 squared + 3 x 10 + 5
  3270.  
  3271.    One way to calculate the value of the number is to calculate each power of
  3272.    10 separately, then multiply each digit by the corresponding power. For
  3273.    example, you can calculate 10 cubed, and then multiply by 2.
  3274.  
  3275.    A much more efficient algorithm combines the calculations for powers of
  3276.    10. The algorithm adds each digit to a running total, then multiplies the
  3277.    total by 10 after every digit but the last. The following pseudo-code
  3278.    represents this algorithm, and assumes that the first character in the
  3279.    string is the most significant digit:
  3280.  
  3281.    initialize total to 0
  3282.    while there's another digit
  3283.        add value of digit to total
  3284.        advance to next digit
  3285.        if no more digits
  3286.            we're done
  3287.        else
  3288.            multiply total by 10
  3289.  
  3290.    A simple C program that calls the procedure might look like this:
  3291.  
  3292.    extern  unsigned int  dectoint( char * );
  3293.    main()
  3294.    {
  3295.        char    digits[81];
  3296.  
  3297.        gets( digits );
  3298.        printf( "Numeric value is: %d", dectoint( digits ) );
  3299.    }
  3300.  
  3301.    The procedure itself could be written in C as:
  3302.  
  3303.    unsigned int dectoint( char *Array)
  3304.    {
  3305.        unsigned int total = 0;       /* Initialize total */
  3306.  
  3307.        while( *Array != '\0' )       /* While there's another digit
  3308.        {
  3309.            total += *Array - '0';    /* Add value to total */
  3310.            Array++;                  /* Advance to next digit */
  3311.            if( *Array == '\0' )      /* If no more digits,  */
  3312.                break;                /*   we're done    */
  3313.            total *= 10;              /* Else, multiply by 10 */
  3314.        }
  3315.        return( total );
  3316.    }
  3317.  
  3318.    This chapter shows how to write the same procedure in assembly language.
  3319.    The assembly-language version will be faster because it can make strategic
  3320.    use of registers and choose optimal instructions. You can write a main
  3321.    module with C code, place the assembly routine in a separate module with a
  3322.    .ASM extension, then link them together by creating a program list.
  3323.  
  3324.    ──────────────────────────────────────────────────────────────────────────
  3325.    NOTE  You can build mixed-language programs by placing both .C and .ASM
  3326.    files in a program list. Place the main module first. In the Assembler
  3327.    Flags dialog box, make sure that you select either Preserve Case or
  3328.    Preserve Extrn (the default). From the QCL command line, use the /Cl
  3329.    (preserve case) or /Cx (preserve case of external symbols) option. QC
  3330.    calls the linker with case sensitivity on, so C and assembler symbols must
  3331.    match exactly.
  3332.    ──────────────────────────────────────────────────────────────────────────
  3333.  
  3334.    Before writing the assembly procedure, we first need to develop a strategy
  3335.    for using registers.
  3336.  
  3337.    The AX (Accumulator) register is ideal for keeping the running total. The
  3338.    algorithm changes this total through both addition and multiplication. The
  3339.    MUL instruction requires the use of AX. By keeping the total in AX at all
  3340.    times, the procedure avoids having to constantly reload this register.
  3341.  
  3342.    The BX register should be used to access the individual digits. The
  3343.    procedure receives the address of the digit string, and then retrieves
  3344.    each ASCII byte through pointer indirection. BX is one of the few
  3345.    registers that supports this operation. SI and DI could also be used this
  3346.    way, but C-generated code requires that SI and DI be preserved. BX can be
  3347.    freely altered.
  3348.  
  3349.    The procedure needs to allocate two more registers: one for holding the
  3350.    multiplication factor (10), and another for adjusting the binary value of
  3351.    the digit. The procedure uses CX and DX for these purposes. In this case,
  3352.    CX and DX are interchangeable. However, we use CX for multiplication now,
  3353.    because in the hex conversion example, CX will be needed for a special
  3354.    kind of multiplication──shifting bits. We use DX as an intermediate
  3355.    location to receive a byte and then add a word to AX.
  3356.  
  3357.    The complete assembly-language module is shown below:
  3358.  
  3359.                .MODEL  small,c
  3360.                .CODE
  3361.  
  3362.    dectoint    PROC    Array:PTR BYTE
  3363.  
  3364.                sub     ax,ax               ; ax = 0
  3365.                mov     bx,Array            ; bx = Array
  3366.                mov     cx,10               ; factor = CX = 10
  3367.                sub     dx,dx               ; dx = 0
  3368.                cmp     BYTE PTR [bx],0     ; Compare byte to NULL
  3369.                je      done                ; If byte=0 we're done
  3370.    top:
  3371.                mov     dl,BYTE PTR [bx]    ; Get next digit
  3372.                sub     dl,'0'              ; Convert numeral
  3373.                add     ax,dx               ; Add to total
  3374.                inc     bx                  ; Point to next byte
  3375.                cmp     BYTE PTR [bx],0     ; Compare byte to NULL
  3376.                je      done                ; If byte=0 we're done
  3377.                mul     cx                  ; AX = AX * 10
  3378.                jmp     SHORT top           ; Goto top of loop
  3379.    done:
  3380.                ret                         ; Exit procedure
  3381.    dectoint    ENDP
  3382.                END
  3383.  
  3384.    We'll examine each section of the module in turn. The first three
  3385.    statements are directives that form part of the module's skeleton. The
  3386.    PROC directive, when used with one or more parameters as it is here,
  3387.    generates code to set the framepointer (BP) properly so that you can
  3388.    access parameters.
  3389.  
  3390.                .MODEL  small,c
  3391.                .CODE
  3392.  
  3393.    dectoint    PROC    Array:PTR BYTE
  3394.  
  3395.    The rest of the module consists of instructions──the actual core of the
  3396.    program. The first four instructions initialize the registers AX, BX, CX,
  3397.    and DX. Note that when initializing a register to 0, the procedure uses
  3398.    SUB in preference to MOV. Any value subtracted from itself leaves zero in
  3399.    the destination operand. Although the result is the same, the SUB
  3400.    instruction is smaller and faster because it involves no immediate data.
  3401.  
  3402.                sub     ax,ax               ; ax = 0
  3403.                mov     bx,Array            ; bx = Array
  3404.                mov     cx,10               ; factor = CX = 10
  3405.                sub     dx,dx               ; dx = 0
  3406.  
  3407.    The next two instructions handle a special case──that of a string
  3408.    containing no digits at all. Recall that the procedure is passed a
  3409.    null-terminated string. The operand BYTE PTR [bx] is a memory operand
  3410.    referring to the byte pointed to by BX. If the string is empty, Array
  3411.    points to a null byte. The two instructions test for a 0 (null) value and
  3412.    jump to the end of the procedure if 0 is detected:
  3413.  
  3414.                cmp     BYTE PTR [bx],0     ; Compare byte to NULL
  3415.                je      done                ; If byte=0 we're done
  3416.  
  3417.    In the CMP instruction above, the BYTE PTR operator is strictly required,
  3418.    because otherwise the assembler would have no way of knowing whether to
  3419.    compare 0 to the byte or a word pointed to by BX. However, when one of the
  3420.    operands is a register (as is the case with the MOV instruction below),
  3421.    the BYTE PTR operator is optional.
  3422.  
  3423.    The next eight instructions consist of a loop executed once for every
  3424.    digit character in the string. The label top indicates the top of the
  3425.    loop, and the first three instructions add the value of the digit to AX:
  3426.  
  3427.    top:
  3428.                mov     dl,BYTE PTR [bx]    ; Get next digit
  3429.                sub     dl,'0'              ; Convert numeral
  3430.                add     ax,dx               ; Add to total
  3431.  
  3432.    The first instruction above retrieves the digit. The next instruction
  3433.    converts the digit's ASCII value to the numeric value by subtracting the
  3434.    value of the character '0' (48 decimal). This statement works because the
  3435.    ASCII character set places all digit characters in sequence from 0 to 9.
  3436.    Finally, the procedure adds the resulting value to the running total
  3437.    stored in AX. Note that the operands in each case are the same size. The
  3438.    first two instructions above access DL, the low byte of DX.
  3439.  
  3440.    The next three instructions advance to the next byte in the string, and
  3441.    test it for equality to zero. Getting the next byte is just a matter of
  3442.    adding the value 1 to BX (with the INC instruction), so that BX points to
  3443.    the next byte. The other two instructions are identical to previous
  3444.    instructions that tested for zero value.
  3445.  
  3446.                inc     bx                  ; Point to next byte
  3447.                cmp     BYTE PTR [bx],0     ; Compare byte to NULL
  3448.                je      done                ; If byte=0 we're done
  3449.  
  3450.    If the next byte is a null byte, the processor jumps to the end of the
  3451.    program. Otherwise, the processor continues executing the bottom of the
  3452.    loop, which multiplies the current total by 10 (stored in CX), and then
  3453.    jumps to the top:
  3454.  
  3455.                mul     CX                  ; AX = AX * 10
  3456.                jmp     SHORT top           ; Goto top of loop
  3457.  
  3458.    Notice the operator SHORT used with the jmp instruction. This optional
  3459.    operator makes the encoded instruction smaller and faster, but it can be
  3460.    used only if the destination of the jump is less than 128 bytes away.
  3461.    SHORT is explained in more detail in Section 9.2.4.2.
  3462.  
  3463.    The loop is now complete. The rest of the module exits and marks the end
  3464.    of the segment and the module. The RET statement causes the assembler to
  3465.    generate instructions to do the following: restore the stack, restore the
  3466.    framepointer (BP), and return properly for the memory model (small) and
  3467.    calling convention (C).
  3468.  
  3469.    done:
  3470.                ret                         ; Exit procedure
  3471.    dectoint    ENDP
  3472.                END
  3473.  
  3474.    Microsoft high-level languages always look for function return values in
  3475.    AX, if two bytes long, or in DX and AX, if four bytes long. If the return
  3476.    value is longer than four bytes, DX:AX points to the value returned. If
  3477.    the return value is one byte, AL contains the value.
  3478.  
  3479.    The C module that calls this procedure looks in AX for the return
  3480.    value──as does all high-level-language code that calls a function
  3481.    returning a two-byte value. In this case, AX already contains the results
  3482.    of the calculation. No further action is required.
  3483.  
  3484.  
  3485.  3.4  Decimal Conversion with Far Data Pointers
  3486.  
  3487.    This section uses the same basic algorithm introduced in the last section,
  3488.    but presents coding techniques for different memory models.
  3489.  
  3490.    The .MODEL directive resolves all differences in the size of code
  3491.    addresses. However, when you use memory models that use far data pointers
  3492.    (compact, large, and huge), you must make some additional adjustments.
  3493.  
  3494.    The program below shows the module rewritten for large memory model. This
  3495.    example works for compact model if large in the first line is replaced
  3496.    with compact.
  3497.  
  3498.                .MODEL  large,c
  3499.                .CODE
  3500.  
  3501.    dectoint    PROC    USES ds, Array:PTR BYTE
  3502.  
  3503.                sub     ax,ax               ; ax = 0
  3504.                lds     bx,Array            ; ds:bx = Array
  3505.                mov     cx,10               ; factor = CX = 10
  3506.                sub     dx,dx               ; dx = 0
  3507.                cmp     BYTE PTR [bx],0     ; Compare byte to NULL
  3508.                je      done                ; If byte=0 we're done
  3509.    top:
  3510.                mov     dl,BYTE PTR [bx]    ; Get next digit
  3511.                sub     dl,'0'              ; Convert numeral
  3512.                add     ax,dx               ; Add to total
  3513.                inc     bx                  ; Point to next byte
  3514.                cmp     BYTE PTR [bx],0     ; Compare byte to NULL
  3515.                je      done                ; If byte=0 we're done
  3516.                mul     cx                  ; AX = AX * 10
  3517.                jmp     SHORT top           ; Goto top of loop
  3518.    done:
  3519.                ret                         ; Exit procedure
  3520.    dectoint    ENDP
  3521.                END
  3522.  
  3523.    This procedure is the same as the one in the last section, except for two
  3524.    lines. The PROC directive now includes a USES clause, and the LDS
  3525.    instruction replaces the first MOV instruction.
  3526.  
  3527.    The procedure loads the DS register with the segment address of Array,
  3528.    thus causing subsequent data references to be relative to the new segment
  3529.    address. However, procedures called from C must preserve DS. The PROC
  3530.    statement, therefore, includes USES ds, which generates code to place DS
  3531.    on the stack.
  3532.  
  3533.    The LDS instruction (Load Data Segment) does the actual loading of the DS
  3534.    register. This instruction is similar to the MOV instruction:
  3535.  
  3536.                mov     bx,Array            ; bx = Array
  3537.                                            ;   2-byte data pointer
  3538.                lds     bx,Array            ; ds:bx = Array
  3539.                                            ;   4-byte data pointer
  3540.  
  3541.    The LDS instruction accomplishes two moves. First, it loads the offset
  3542.    portion of the pointer into the specified register (BX). Second, it loads
  3543.    the segment portion of the pointer into DS.
  3544.  
  3545.    ──────────────────────────────────────────────────────────────────────────
  3546.    NOTE   For the LDS and LES instructions to work properly, the segment
  3547.    portion must be stored in the upper word of the four-byte (far) pointer. C
  3548.    meets this requirement by always pushing the segment portion of the
  3549.    pointer on the stack first. (The stack grows downward.) In your own
  3550.    programs, you declare far pointers with the DD directive. You initialize
  3551.    them by loading a segment address into the upper word of the pointer
  3552.    variable and an offset address into the lower word.
  3553.    ──────────────────────────────────────────────────────────────────────────
  3554.  
  3555.  
  3556.  3.4.1  Writing a Model-Independent Procedure
  3557.  
  3558.    In the case of this procedure, the use of the LDS instruction is most
  3559.    convenient. Once DS is loaded with the new segment address, all subsequent
  3560.    memory references are automatically correct. No further adjustments are
  3561.    needed.
  3562.  
  3563.    The simplicity of this technique makes it easy to write a module that is
  3564.    completely independent of memory models. This module can then be linked
  3565.    with any C program. To adjust memory model, you simply change the .MODEL
  3566.    directive, and recompile. In fact, the memory model itself can even be
  3567.    specified with a compile flag so that source code never need change.
  3568.  
  3569.    The model-independent version contains only a few lines different from the
  3570.    previous example:
  3571.  
  3572.    %           .MODEL  mem,c
  3573.                .CODE
  3574.  
  3575.    dectoint    PROC    USES ds, Array:PTR BYTE
  3576.  
  3577.                sub     ax,ax               ; ax = 0
  3578.                IF      @DataSize
  3579.                lds     bx,Array            ; ds:bx = Array
  3580.                ELSE
  3581.                mov     bx,Array            ; bx = Array
  3582.                ENDIF
  3583.  
  3584.    The .MODEL directive operates on an undefined variable, mem. You define
  3585.    this variable on the QCL command line or in the Assembler Flags dialog
  3586.    box. For example, to assemble with QCL in compact model, enter the
  3587.    following text in the defines text box:
  3588.  
  3589.    /Dmem=compact
  3590.  
  3591.    The IF, ELSE, and ENDIF directives cause conditional assembly. The
  3592.    @DataSize predefined macro is equal to 1 (true) if the memory model uses
  3593.    far data pointers, and 0 (false) otherwise. The statement IF @DataSize
  3594.    begins a conditional-assembly block that assembles the LDS instruction if
  3595.    the memory model uses far data pointers; it assembles the MOV instruction
  3596.    otherwise.
  3597.  
  3598.    For more information on conditional assembly, see Chapter 10, "Assembling
  3599.    Conditionally."
  3600.  
  3601.    The USES clause is retained for all memory models, since even with small
  3602.    model it does no harm. However, to increase efficiency, you may wish to
  3603.    include the PROC statement inside conditional-assembly blocks.
  3604.  
  3605.  
  3606.  3.4.2  Accessing Far Data through ES
  3607.  
  3608.    The LDS instruction is inconvenient if you need to access items in the
  3609.    default data segment, because you have no guarantee that DS still points
  3610.    to that area of memory. Therefore, it's sometimes more efficient to leave
  3611.    DS alone and use the ES register to access far data.
  3612.  
  3613.    The standard C memory models all use the LES instruction to access far
  3614.    data. You can also use this method, but it is not required, since it has
  3615.    no effect on the interface between modules. Give the LES instruction to
  3616.    load a far data pointer, which will load the ES register with the new
  3617.    segment address. Then give the ES override whenever you refer to data in
  3618.    the far segment. This method requires alteration of all instructions that
  3619.    access the string data:
  3620.  
  3621.                les     bx,Array            ; es:bx = Array
  3622.                .
  3623.                .
  3624.                .
  3625.                cmp     es:BYTE PTR [bx],0  ; Compare byte to NULL
  3626.  
  3627.    Once ES is loaded with the segment address of far data, access objects in
  3628.    the default data area (the segment containing near data) as you normally
  3629.    would. Use the ES override to access the far data.
  3630.  
  3631.  
  3632.  3.5  Hexadecimal Conversion Example
  3633.  
  3634.    The following example builds on the decimal example in Section 3.3,
  3635.    adding the additional logic needed to convert hexadecimal rather than
  3636.    decimal strings.
  3637.  
  3638.    Hexadecimal conversion can use an algorithm similar to the one used
  3639.    earlier for decimal conversion, with these adjustments made:
  3640.  
  3641.    ■  The procedure multiplies the running total by 16, not 10.
  3642.  
  3643.    ■  The procedure converts the letters A-F to numeric values, in addition
  3644.       to converting the numerals 0-9.
  3645.  
  3646.    You could make the first adjustment by loading CX with 16 instead of 10. A
  3647.    much more efficient method is to use the SHL (Shift Left) instruction to
  3648.    shift an object's bits left by four places. This effectively multiplies
  3649.    the object by 16.
  3650.  
  3651.    The second adjustment requires more complex logic. Hexadecimal digits can
  3652.    consist of either letters or numerals. The procedure must consider three
  3653.    different cases──one for each sequence of hexadecimal characters:
  3654.  
  3655.    Range of Characters Conversion Required
  3656.    ──────────────────────────────────────────────────────────────────────────
  3657.    0-9                 Convert to face value. Subtract ASCII value of '0'.
  3658.  
  3659.    A-F, and a-f        Convert to values 10-15. Convert all letters to
  3660.                        uppercase, then subtract ASCII value of 'A' and add
  3661.                        10.
  3662.  
  3663.  
  3664.    We convert all letters to uppercase in an optimized fashion by taking
  3665.    advantage of the ASCII coding sequence. Uppercase letters are coded as 41H
  3666.    onward. Lowercase letters are coded as 61H onward. Consequently, each
  3667.    lowercase letter differs from the corresponding uppercase letter by
  3668.    exactly one bit. We use the AND instruction, with the immediate operand
  3669.    0DFH, to mask out this bit. This operation has the effect of setting the
  3670.    third highest bit to 0.
  3671.  
  3672.             0110 0001  61h = 'a'     0100 0001  41h = 'A'
  3673.    AND      1101 1111  DFh           1101 1111  DFh
  3674.             ======================   ======================
  3675.    result   0100 0001  41h = 'A'     0100 0001  41h = 'A'
  3676.  
  3677.             0110 0010  62h = 'b'     0100 0010  42h = 'B'
  3678.    AND      1101 1111  DFh           1101 1111  DFh
  3679.             ======================   ======================
  3680.    result   0100 0010  42h = 'B'     0100 0010  42h = 'B'
  3681.  
  3682.    The beauty of the operation is that it converts lowercase letters to
  3683.    uppercase, but leaves uppercase letters alone. If the third highest bit is
  3684.    already 0 (as is the case with uppercase letters), doing an AND operation
  3685.    with 0DFH has no effect. This operation removes the need to handle
  3686.    lowercase letters as a separate case.
  3687.  
  3688.    The revised algorithm does the following:
  3689.  
  3690.    initialize total to zero
  3691.    while there's another digit
  3692.        move byte to temporary location
  3693.        if ascii value < 'A'
  3694.            Subtract '0'
  3695.        else
  3696.            Convert lowercase to uppercase
  3697.            Subtract 'A'-10
  3698.        add byte value to total
  3699.        advance to next digit
  3700.        if no more digits
  3701.            we're done
  3702.        else
  3703.            shift total left by four bits
  3704.  
  3705.    The assembly-language code below implements this algorithm. The code tests
  3706.    for each range, performing a different conversion for each case. Note the
  3707.    use of JB (Jump If Below), which jumps to the specified label if the
  3708.    previous comparison or subtraction produced a negative value──that is, if
  3709.    the first operand is less than the second.
  3710.  
  3711.                .MODEL  small,c
  3712.                .CODE
  3713.  
  3714.    hextoint    PROC    Array:PTR BYTE
  3715.  
  3716.                sub     ax,ax             ; ax = 0
  3717.                mov     bx,Array          ; bx = Array
  3718.                mov     cl,4              ; Prepare to shift left by 4
  3719.                sub     dx,dx             ; dx = 0
  3720.                cmp     BYTE PTR [bx],0   ; Compare byte to NULL
  3721.                je      done              ; if byte=0 we're done
  3722.    top:
  3723.                mov     dl,BYTE PTR [bx]  ; Move byte to DL
  3724.                cmp     dl,'A'            ; ASCII value >= 'A'?
  3725.                jae     isletter          ; If so, goto isletter
  3726.                sub     dl,'0'            ; Convert ascii to numeric
  3727.                jmp     addbyte           ; Go add value of byte
  3728.    isletter:
  3729.                and     dl,0DFh           ; Convert to uppercase
  3730.                sub     dl,'A'-10         ; Convert ascii to numeric
  3731.    addbyte:
  3732.                add     ax,dx             ; Add value to total
  3733.                inc     bx                ; Point to next byte
  3734.                cmp     BYTE PTR [bx],0   ; Compare byte to NULL
  3735.                je      done              ; If byte=0 we're done
  3736.                shl     ax,cl             ; AX = AX * 16
  3737.                jmp     SHORT top         ; Goto top of loop
  3738.    done:
  3739.                ret
  3740.    hextoint    ENDP
  3741.                END
  3742.  
  3743.    The beginning of the procedure initializes the CL register to 4. This step
  3744.    is necessary, because you can use the SHL instruction (Shift Left) in only
  3745.    two ways: you can shift by exactly one bit, or you can shift by the number
  3746.    of places indicated in CL. Clearly, using CL is more efficient than a
  3747.    sequence of four shift instructions.
  3748.  
  3749.    The main loop reads a character, tests it, and makes one basic decision:
  3750.    is the character a letter or not? This test takes advantage of the ASCII
  3751.    coding sequence. If the value of the character is equal to or greater than
  3752.    'A', it cannot be one of the digits 0-9. The procedure uses the JAE
  3753.    instruction (Jump If Above or Equal) to test for this condition.
  3754.  
  3755.    top:
  3756.                mov     dl,BYTE PTR [bx]  ; Move byte to DL
  3757.                cmp     dl,'a'            ; ASCII value >= 'A'?
  3758.                jae     isletter          ; If so, goto isletter
  3759.  
  3760.    If the character is a letter, the procedure first converts the letter to
  3761.    uppercase──using an AND instruction that converts lowercase letters but
  3762.    leaves uppercase letters unchanged. The following instruction can then
  3763.    properly handle all letters the same way, regardless of their original
  3764.    case:
  3765.  
  3766.    isletter:
  3767.                and     dl,0DFh           ; Convert to uppercase
  3768.                sub     dl,'A'-10         ; Convert ascii to numeric
  3769.  
  3770.    For simplicity, the procedure accepts invalid letters. You could easily
  3771.    enhance it to verify that the letters are hexadecimal.
  3772.  
  3773.  
  3774.  
  3775.  ────────────────────────────────────────────────────────────────────────────
  3776.  Chapter 4:  Writing Stand-Alone Assembly Programs
  3777.  
  3778.  
  3779.    With QuickAssembler, you can write stand-alone assembly programs to
  3780.    produce small, efficient utilities. For example, you might write a utility
  3781.    in assembly language to count the number of lines or paragraphs in a file.
  3782.    These programs start and end with assembly code and generally do not
  3783.    involve any links to high-level languages.
  3784.  
  3785.    Stand-alone assembly programs can yield remarkably small .EXE files. They
  3786.    require relatively little space, because they do not include the start-up
  3787.    code for a high-level language. And often you can make your assembly
  3788.    program even smaller by converting it to a .COM file as shown in this
  3789.    chapter. Some useful .COM files take up less than 100 bytes of memory.
  3790.  
  3791.    This chapter first describes the directives you need to write stand-alone
  3792.    assembly programs, reviews instructions used in the chapter's examples,
  3793.    and then presents a simple stand-alone program. Next, Sections 4.4-4.6
  3794.    look closely at each segment of the program: stack, data, and code.
  3795.    Finally, the chapter describes how to create a program in the .COM format.
  3796.  
  3797.  
  3798.  4.1  A Skeleton for Stand-Alone Programs
  3799.  
  3800.    This chapter uses the simplified segment directives described in the
  3801.    previous chapter, and introduces three more directives──.STACK, .DATA, and
  3802.    .STARTUP. The simplified segment directives produce programs using the
  3803.    Microsoft standard segment format.
  3804.  
  3805.    This format is not required, since your stand-alone program need not be
  3806.    compatible with a high-level-language module. However, the standard format
  3807.    is convenient because you can specify a number of different memory models,
  3808.    and you are freed from having to specify segment names, attributes, and
  3809.    register assumptions.
  3810.  
  3811.    ──────────────────────────────────────────────────────────────────────────
  3812.    NOTE  Occasionally, you may need a customized segment structure. Linking
  3813.    assembly code to a non-Microsoft language is the most common situation
  3814.    that requires customized segments. QuickAssembler lets you use full
  3815.    segment definitions any time you need to customize segments. However, you
  3816.    should find that simplified segment directives support the vast majority
  3817.    of assembly-language programming you do──even when you write .COM files.
  3818.    ──────────────────────────────────────────────────────────────────────────
  3819.  
  3820.    The skeleton for the programs in this chapter includes a stack, data, and
  3821.    code segment. Note that one of the directives, .MODEL, will change when
  3822.    you alter the memory model. The other statements remain the same.
  3823.  
  3824.                .MODEL   small               ; Use small memory model
  3825.  
  3826.                .STACK   100h                ; Declare 256-byte stack
  3827.  
  3828.                .DATA
  3829.    ;
  3830.    ;    (place data declarations here)
  3831.    ;
  3832.                .CODE
  3833.                .STARTUP                     ; Set up DS, SS, and SP registers
  3834.    ;
  3835.    ;    (place executable code here)
  3836.    ;
  3837.                END
  3838.  
  3839.    Sections 4.1.1-4.1.3 examine each of the statements in this skeleton more
  3840.    closely.
  3841.  
  3842.  
  3843.  4.1.1  The .MODEL Directive
  3844.  
  3845.    The .MODEL directive performs the same role that it did in the previous
  3846.    chapter; it defines the overall attributes of the module. Note, however,
  3847.    that with a stand-alone program, a language type is not always required. A
  3848.    language type is useful when a module contains one or more procedures.
  3849.    Otherwise, you need only type .MODEL followed by a memory model:
  3850.  
  3851.                .MODEL   small               ; Use small memory model
  3852.  
  3853.    The memory model can be TINY, SMALL, MEDIUM, COMPACT, LARGE, or HUGE. Most
  3854.    of these memory models may be familiar to you if you have used QuickC. For
  3855.    a complete description of each memory model, see Section 5.1.1.
  3856.  
  3857.    The TINY memory model is new; it alone results in the creation of a .COM
  3858.    file rather than a .EXE file. Section 4.8, "Creating .COM Files," gives a
  3859.    complete example featuring the use of tiny memory model.
  3860.  
  3861.    Generally, to change memory model you change the .MODEL directive. You
  3862.    also change the way you load and use data pointers, as described in
  3863.    Chapter 3, "Writing Assembly Modules for C Programs." With these changes
  3864.    made, many programs can readily be reassembled for a new memory model.
  3865.    (However, as you'll see in Chapter 5, "Defining Segment Structure," you
  3866.    cannot use .FARDATA segments in tiny, small, or medium model, and this may
  3867.    require further revision of code in some cases.)
  3868.  
  3869.  
  3870.  4.1.2  The .STACK, .CODE, and .DATA Directives
  3871.  
  3872.    Each of the segment directives──.STACK, .CODE, and .DATA──declares the
  3873.    beginning of a segment.
  3874.  
  3875.    The code and data segments begin with .CODE and .DATA, respectively. Each
  3876.    of these segments continues to the next segment directive or the end of
  3877.    the program. The data segment contains data and symbolic constant
  3878.    declarations. The code segment contains instructions.
  3879.  
  3880.    However, the stack segment consists of only one line:
  3881.  
  3882.    .STACK [[size]]
  3883.  
  3884.    By default, QuickAssembler interprets size according to the current radix,
  3885.    which by default is decimal. You can specify a hexadecimal constant by
  3886.    using the H suffix. (Example: 200h.) The size argument is optional. If you
  3887.    leave it out, the assembler creates a stack 1024 bytes long.
  3888.  
  3889.    Unless the program is written in tiny memory model, you should always
  3890.    declare a stack segment in your main module. Section 4.4, "Inside the
  3891.    Stack Segment," explains the purpose of this segment.
  3892.  
  3893.  
  3894.  4.1.3  The .STARTUP Directive
  3895.  
  3896.    Unlike C programs, assembly-language programs have to initialize register
  3897.    values. Specifically, the program has to initialize DS, the Data Segment
  3898.    register; CS and IP, which point to the first instruction to execute; and
  3899.    SS and SP, the stack registers.
  3900.  
  3901.    By far the easiest way to initialize all these registers is to just
  3902.    include .STARTUP, a simple directive that takes no arguments:
  3903.  
  3904.                .STARTUP         ; Set up DS, SS, and SP registers
  3905.  
  3906.    When you use this directive, the assembler generates code to initialize
  3907.    your registers the way Microsoft high-level languages do. The generated
  3908.    code is similar to some of the instructions in the C start-up code. The
  3909.    directive takes care of minimal start-up, but many programs will need to
  3910.    do additional start-up tasks, such as releasing unused memory.
  3911.  
  3912.    ──────────────────────────────────────────────────────────────────────────
  3913.    NOTE  The start-up sequence adjusts SS and SP so that SS is equal to DS.
  3914.    This starting condition gives you some advantages. If you later have to
  3915.    alter the value of DS, you can always access a data object as an indirect
  3916.    operand using BP, or through an SS segment override. To avoid this
  3917.    starting sequence, so that the stack and data are separate physical
  3918.    segments, use the farStack keyword with the .MODEL directive, as described
  3919.    in Section 5.1.3.
  3920.    ──────────────────────────────────────────────────────────────────────────
  3921.  
  3922.  
  3923.  4.2  Instructions Used in This Chapter
  3924.  
  3925.    This section summarizes the instructions used in this chapter. Because the
  3926.    program examples are simple, only a very few of the 80-odd instructions of
  3927.    the 8086 are featured here.
  3928.  
  3929.    This chapter features four instructions:
  3930.  
  3931.    Instruction         Description
  3932.    ──────────────────────────────────────────────────────────────────────────
  3933.    MOV destination,    Moves source to destination
  3934.    source
  3935.    INT number          Generates the indicated interrupt signal, causing
  3936.                        processor to call a memory-resident interrupt routine
  3937.  
  3938.    DEC destination     Decrement──subtracts 1 from destination
  3939.  
  3940.    JNZ label           Jump If Not Zero──jumps to label if result of last
  3941.                        operation was not zero
  3942.  
  3943.  
  3944.    Most of the instructions above were introduced in Chapter 2, "Introducing
  3945.    8086 Assembly Language." The new instruction is INT.
  3946.  
  3947.    The INT instruction generates a software interrupt signal, causing the
  3948.    processor to call an interrupt service routine usually residing in a DOS
  3949.    or ROM-BIOS memory area. This call is much like a procedure call; the
  3950.    processor executes a specific function and returns to the program when the
  3951.    routine is complete.
  3952.  
  3953.    There are two major differences between an interrupt call and a procedure
  3954.    call. First, instead of calling a procedure you have written, an INT
  3955.    instruction calls a DOS system routine or ROM-BIOS service. These
  3956.    low-level routines carry out a variety of basic operations, such as
  3957.    reading the keyboard, writing to the screen, or using the file system.
  3958.    Most DOS services are accessed through interrupt 21H (33 decimal).
  3959.  
  3960.    The second major difference is syntactic. You follow the INT keyword by an
  3961.    interrupt number (in the range 0 to 255), rather than a procedure name. In
  3962.    many cases, you further specify the interrupt routine by loading AH with a
  3963.    function number.
  3964.  
  3965.  
  3966.  4.3  A Program That Says Hello
  3967.  
  3968.    The following sample program prints Hello world and then successfully
  3969.    exits back to DOS. You can use this program as a template and insert your
  3970.    own code and data.
  3971.  
  3972.                .MODEL  small                ; Use small model
  3973.  
  3974.                .STACK  100h                 ; Allocate 256-byte stack
  3975.  
  3976.                .DATA
  3977.    message     DB    "Hello, world.",13,10  ; Message to print
  3978.    lmessage    EQU   $ - message            ; Determine length of message
  3979.                .CODE
  3980.                .STARTUP                     ; Use standard startup code
  3981.  
  3982.                mov   bx,1                   ; Load 1 - file handle
  3983.                                             ;   for standard output
  3984.                mov   cx,lmessage            ; Load length of message
  3985.                mov   dx,OFFSET message      ; Load address of message
  3986.                mov   ah,40h                 ; Load no. of DOS Write function
  3987.                int   21h                    ; Call interrupt 21H (DOS)
  3988.  
  3989.                mov   ax,4c00h               ; Load no. of DOS Exit function
  3990.                                             ;   in AH, and 0 exit code in AL
  3991.                int   21h                    ; Call interrupt 21H (DOS)
  3992.  
  3993.                END
  3994.  
  3995.    The first statement determines the memory model of the program:
  3996.  
  3997.                .MODEL  small                ; Use small model
  3998.  
  3999.    This statement specifies small memory model, which places code and data in
  4000.    two separate segments, each of which cannot exceed 64K.
  4001.  
  4002.    The next few sections consider the rest of this program──stack, data, and
  4003.    code.
  4004.  
  4005.  
  4006.  4.4  Inside the Stack Segment
  4007.  
  4008.    The stack segment is the easiest to create, because with simplified
  4009.    segment directives you enter only one statement:
  4010.  
  4011.                .STACK  100h                  ; Allocate 256-byte stack
  4012.  
  4013.    Each processor or interrupt call uses up stack space. The stack stores
  4014.    return addresses, parameters, and local variables for each procedure
  4015.    called. When a procedure or interrupt routine returns, the stack space it
  4016.    used is restored. The more procedure calls your program makes without
  4017.    returning, the more stack area it requires. Programs that nest many
  4018.    procedures or use recursion (in which a procedure calls itself repeatedly)
  4019.    may require large stacks. Unfortunately, there is no formula for
  4020.    determining how large a stack is needed.
  4021.  
  4022.    A 256-byte stack (100 hexadecimal) is adequate for most small programs.
  4023.    For this sample program, which makes one interrupt call but no procedure
  4024.    calls, 256 bytes provides an ample margin of error.
  4025.  
  4026.    You can also create a stack by using full segment definitions. See Section
  4027.    5.2, "Full Segment Definitions," for more information.
  4028.  
  4029.  
  4030.  4.5  Inside the Data Segment
  4031.  
  4032.    A single keyword declares the beginning of the segment:
  4033.  
  4034.                .DATA
  4035.  
  4036.    QuickAssembler considers all statements following this line to lie in the
  4037.    data segment, up until the next segment declaration or END directive. The
  4038.    END directive marks the end of the source file.
  4039.  
  4040.    The next two statements are directives that declare a string of characters
  4041.    and a symbolic constant:
  4042.  
  4043.    message     DB     "Hello, world.",13,10  ; Message to print
  4044.    lmessage    EQU    $ - message            ; Determine length of message
  4045.  
  4046.    The first statement above declares a series of bytes. The label message is
  4047.    a symbolic name that QuickAssembler associates with the string's starting
  4048.    address.
  4049.  
  4050.    The assembler allocates 15 bytes in the data segment, and initializes
  4051.    these bytes to the ASCII values for H, e, l, l, o, and so forth. The
  4052.    values 13 and 10 indicate a carriage return and line feed, respectively,
  4053.    causing the program to move the cursor to the beginning of the next line
  4054.    when it prints the string.
  4055.  
  4056.    The second directive in the data segment declares a symbolic constant
  4057.    equal to the length of the string:
  4058.  
  4059.    lmessage    EQU    $ - message            ; Determine length of message
  4060.  
  4061.    Again, the item in the first column, lmessage, is the label of the
  4062.    statement. The EQU directive equates the label with the value of the
  4063.    operand itself. EQU does not allocate memory.
  4064.  
  4065.    The operand field contains $ - message, which in this case equals 15. We
  4066.    could just as easily have entered 15 in the operand field. However, the
  4067.    item $ - message is guaranteed to be equal to the length of the string,
  4068.    even if you later rewrite the initial string value.
  4069.  
  4070.    The dollar sign ($) is the "location counter," which represents the
  4071.    current address of the statement. QuickAssembler translates the full
  4072.    expression as "Take the current address ($) and subtract the address of
  4073.    message." The current address is one byte after the end of the string.
  4074.    Thus, $ - message is automatically equal to the length of the string.
  4075.  
  4076.  
  4077.  4.6  Inside the Code Segment
  4078.  
  4079.    A single keyword declares the beginning of the code segment:
  4080.  
  4081.                .CODE
  4082.  
  4083.    The code segment consists of all statements between .CODE and the END
  4084.    statement, which marks the end of the source code. In this example, all
  4085.    the statements in the code segment, aside from .STARTUP, are instructions.
  4086.  
  4087.    The program has three basic tasks. Each instruction helps carry out one of
  4088.    these operations:
  4089.  
  4090.    1. Initialize registers
  4091.  
  4092.    2. Call a DOS function to print the message
  4093.  
  4094.    3. Call a DOS function to exit the program gracefully
  4095.  
  4096.    The .STARTUP directive initializes registers. If you write a main module
  4097.    without this directive, you must explicitly initialize DS, CS, and IP.
  4098.    Furthermore, if you want SS to equal DS (which gives some programming
  4099.    advantages), you must adjust both SS and SP.
  4100.  
  4101.    To see how to initialize registers without the use of .STARTUP, see
  4102.    Chapter 5, "Defining Segment Structure."
  4103.  
  4104.    After registers are initialized, a series of five instructions makes the
  4105.    call to DOS that prints the message:
  4106.  
  4107.                mov   bx,1                   ; Load 1 - file handle for
  4108.                                             ;   standard output
  4109.                mov   cx,lmessage            ; Load length of message
  4110.                mov   dx,OFFSET message      ; Load address of message
  4111.                mov   ah,40h                 ; Load no. of DOS Write function
  4112.                int   21h                    ; Call interrupt 21H (DOS)
  4113.  
  4114.    The first four instructions prepare for the DOS call. Interrupt calls
  4115.    generally use registers to receive parameters. Unlike procedure calls,
  4116.    they do not reference the stack for this information. The DOS Write
  4117.    function uses the following registers to receive data:
  4118.  
  4119.    Register            Data
  4120.    ──────────────────────────────────────────────────────────────────────────
  4121.    AH                  Selects the DOS function. 40H is the Write function.
  4122.  
  4123.    BX                  File handle to which to write. The number 1 is a
  4124.                        reserved file handle that always corresponds to
  4125.                        standard output. "Standard output" is normally
  4126.                        synonymous with the computer screen, unless you
  4127.                        redirect program output. If you were writing to a
  4128.                        file, you would first open the file and use the file
  4129.                        handle returned by the DOS open-file function.
  4130.  
  4131.    CX                  Length of the message. The second statement in the
  4132.                        data segment determined this length.
  4133.  
  4134.    DS:DX               The beginning address of the actual message text.
  4135.                        Remember that DS was loaded earlier with the address
  4136.                        of the data segment, so it does not need to be
  4137.                        reloaded now.
  4138.  
  4139.  
  4140.    This procedure uses the OFFSET operator to load DX with the address of the
  4141.    message. Although variables are translated to addresses, the processor
  4142.    normally interprets a variable address as a memory operand──that is, the
  4143.    processor operates on the data at the address, not the address itself.
  4144.  
  4145.    The OFFSET operator extracts the offset portion of the address and turns
  4146.    it into an immediate operand. If the OFFSET operator was not used the DOS
  4147.    routine would not receive the address of message, but would instead
  4148.    receive the value of the first byte. The OFFSET operator is similar to the
  4149.    address operator (&) in C. Use it whenever you need to pass an address
  4150.    rather than a value.
  4151.  
  4152.    After the interrupt service returns, the AX register contains the number
  4153.    of bytes written. The programs in this chapter do not use this return
  4154.    value, but a more sophisticated program might. In particular, if AX
  4155.    (number of bytes written) is less than CX (number of bytes requested to be
  4156.    written), then an error has occurred.
  4157.  
  4158.    Each DOS function has its own conventions for receiving data in different
  4159.    registers. Consult the Microsoft MS-DOS Programmer's Reference for a
  4160.    complete description of each function. The Assembler Contents selection
  4161.    from the Help menu also describes the major DOS functions.
  4162.  
  4163.    ──────────────────────────────────────────────────────────────────────────
  4164.    NOTE  Each DOS function has conventions for getting and returning values
  4165.    in registers and flags. Bear in mind that values placed in any of these
  4166.    registers may change. If you need to preserve register values before
  4167.    making a DOS call, use the PUSH and POP instructions. See Section 13.4.1,
  4168.    "Pushing and Popping," for more information on how to preserve register
  4169.    values.
  4170.    ──────────────────────────────────────────────────────────────────────────
  4171.  
  4172.    The INT instruction makes the actual call to DOS. The interrupt number for
  4173.    the majority of DOS functions is 21H. You use different interrupt numbers
  4174.    to call ROM-BIOS services.
  4175.  
  4176.    The final two instructions cause the program to terminate operation and
  4177.    return control to DOS. High-level language programmers can ignore the need
  4178.    to exit a program explicitly, if they like. But when you write a
  4179.    stand-alone assembly program, you don't have this luxury. The program must
  4180.    exit explicitly. Otherwise, the processor continues to execute random
  4181.    instructions after the end of the program, making the system appear to
  4182.    crash.
  4183.  
  4184.    The DOS Exit function (service 4CH) is the preferred method for exiting
  4185.    back to DOS. This function uses two register values:
  4186.  
  4187.    Register            Data
  4188.    ──────────────────────────────────────────────────────────────────────────
  4189.    AH                  Selects the DOS function. 4CH is the Exit function.
  4190.  
  4191.    AL                  Exit code. Batch files can use this exit code as an
  4192.                        "errorlevel" indicator. An exit code of 0 usually
  4193.                        indicates no error.
  4194.  
  4195.  
  4196.    A single instruction loads both registers:
  4197.  
  4198.                mov   ax,4c00h                   ; Load number of DOS Exit func
  4199.                                                 ;   in AH, and 0 exit code in
  4200.  
  4201.    A single MOV instruction actually moves data into two registers──AH and
  4202.    AL. AH is loaded with 4CH, the function number for the DOS exit function,
  4203.    and AL is loaded with 0, an exit code indicating no error.
  4204.  
  4205.    Finally, another INT instruction calls DOS.
  4206.  
  4207.                int   21h                        ; Call interrupt 21H (DOS)
  4208.  
  4209.  
  4210.  4.7  Making the Program Repeat Itself
  4211.  
  4212.    Once you understand the template for writing stand-alone programs, you can
  4213.    alter the sample program given above and generate your own code. This
  4214.    section alters the sample program so that it prints out a different
  4215.    message, and prints it ten times.
  4216.  
  4217.    The new sample program is listed below:
  4218.  
  4219.                .MODEL  small                    ; Use small model
  4220.  
  4221.                .STACK  100h                     ; Allocate 256-byte stack
  4222.  
  4223.                .DATA
  4224.    message     DB    "Hello, ten times.",13,10  ; Message to print
  4225.    lmessage    EQU   $ - message                ; Determine length of message
  4226.    count       DW    10
  4227.  
  4228.                .CODE
  4229.                .STARTUP                         ; Use standard startup code
  4230.  
  4231.                mov   bx,1                       ; Load 1 - file handle for
  4232.                                                 ;   standard output
  4233.                mov   cx,lmessage                ; Load length of message
  4234.                mov   dx,OFFSET message          ; Load address of message
  4235.    printit:    mov   ah,40h                     ; Load no. of DOS Write functi
  4236.                int   21h                        ; Call interrupt 21H (DOS)
  4237.  
  4238.                dec   count                      ; count = count-1
  4239.                jnz   printit                    ; if count > 0, print again
  4240.  
  4241.                mov   ax,4c00h                   ; Load DOS 4C function number
  4242.                                                 ;   in AH, and 0 exit code in
  4243.                int   21h                        ; Call interrupt 21H (DOS)
  4244.  
  4245.                END
  4246.  
  4247.    Note the following changes:
  4248.  
  4249.    ■  The string data is different.
  4250.  
  4251.    ■  The data segment includes a new variable, count.
  4252.  
  4253.    ■  One of the instructions is now labeled printit.
  4254.  
  4255.    ■  Two additional instructions decrement count, then loop back to the
  4256.       label printit if count is greater than zero.
  4257.  
  4258.    The string data is longer than before, and QuickAssembler must allocate
  4259.    more bytes than in the previous version of the program. However, the EQU
  4260.    statement that follows guarantees that the assembler still calculates
  4261.    string length correctly:
  4262.  
  4263.    message     DB    "Hello, ten times.",13,10 ; Message to print
  4264.    lmessage    EQU   $ - message               ; Determine length of message
  4265.  
  4266.    The new variable is actually a memory location of word size (two bytes).
  4267.    QuickAssembler allocates another two bytes in the data segment, and
  4268.    initializes these bytes:
  4269.  
  4270.    count       DW    10
  4271.  
  4272.    The label count becomes associated with the address of the data, and the
  4273.    number 10 is the initial value placed at this memory location. However,
  4274.    the value can change.
  4275.  
  4276.    The instruction mov ah,40h now has a label, because the program needs to
  4277.    return here to repeat the print operation. Not all instructions need a
  4278.    label──only those that the program may need to jump to directly.
  4279.  
  4280.    The two new instructions cause the program to repeat the print operation
  4281.    ten times:
  4282.  
  4283.                dec   count                     ; count = count-1
  4284.                jnz   printit                   ; if count > 0, print again
  4285.  
  4286.    The DEC instruction subtracts 1 from the memory location count, and sets
  4287.    processor flags according to the result of the operation. JNZ then jumps
  4288.    to the specified label if the result was not zero. The combined effect of
  4289.    these two instructions is to repeat the previous instructions (from
  4290.    printit onward) ten times. To change the number of repetitions, initialize
  4291.    count with a different value.
  4292.  
  4293.    Note that the DOS print function returns a value in the register
  4294.    AX──specifically, the number of bytes written. The program jumps back to
  4295.    printit so that AH is reloaded before the call to DOS.
  4296.  
  4297.    You can optimize this program further by using a register instead of the
  4298.    memory location count. For example, to use the register SI as the counter,
  4299.    follow these steps:
  4300.  
  4301.    ■  Remove the declaration of count.
  4302.  
  4303.    ■  Initialize SI to 10 at the beginning of the program with the
  4304.       instruction mov si,10.
  4305.  
  4306.    ■  Decrement SI instead of count near the bottom of the loop.
  4307.  
  4308.    With this program, it's safe to use SI as the counter, since SI is not
  4309.    needed for any other purpose. However, some programs make special use of
  4310.    SI. In these cases, it may be more efficient to place the count in a
  4311.    variable.
  4312.  
  4313.  
  4314.  4.8  Creating .COM Files
  4315.  
  4316.    You can use QuickAssembler to produce .COM files as well as .EXE files.
  4317.    (However, these programs cannot contain any C modules.) Most of the memory
  4318.    models, ranging from small to large, produce a .EXE file. The tiny memory
  4319.    model is special because it alone supports creation of a .COM file.
  4320.  
  4321.    ──────────────────────────────────────────────────────────────────────────
  4322.    NOTE  To produce a .COM file, you must not only use tiny memory model, but
  4323.    also select Generate COM File from the Linker Flags dialog box (choose
  4324.    Make from the Options menu), or else give the /TINY linker option on the
  4325.    QCL command line.
  4326.    ──────────────────────────────────────────────────────────────────────────
  4327.  
  4328.    Each .COM file has only one physical segment and is limited in size to a
  4329.    total of 64K. A .COM file has no executable-file header or
  4330.    relocation-table entries. Because DOS doesn't have to examine a file
  4331.    header or adjust relocatable segment addresses, it loads the .COM file
  4332.    slightly faster.
  4333.  
  4334.    DOS initializes all segment registers (including DS) to point to the first
  4335.    available memory address. The Stack Pointer, SP, is set to 64K above the
  4336.    start of the program. Unlike .EXE files, .COM files have no definite stack
  4337.    area. Instead, the stack starts at offset address FFFE hexadecimal and
  4338.    continues to grow downward until it overlaps code and data areas. At that
  4339.    point, program failure is likely.
  4340.  
  4341.    Simplified segment directives in QuickAssembler now provide direct support
  4342.    for .COM files. The template is, in fact, smaller than the template for a
  4343.    .EXE file.
  4344.  
  4345.    The code below shows the example in Section 4.3, "A Program That Says
  4346.    Hello," revised to produce a .COM file:
  4347.  
  4348.                .MODEL  tiny                 ; Produce a .COM file
  4349.  
  4350.                .DATA
  4351.    message     DB    "Hello, world.",13,10  ; Message to print
  4352.    lmessage    EQU   $ - message            ; Determine length of message
  4353.                .CODE
  4354.                .STARTUP
  4355.                mov   bx,1                   ; Load 1 - file handle for
  4356.                                             ;   standard output
  4357.                mov   cx,lmessage            ; Load length of message
  4358.                mov   dx,OFFSET message      ; Load address of message
  4359.                mov   ah,40h                 ; Load no. of DOS Write function
  4360.                int   21h                    ; Call interrupt 21H (DOS)
  4361.  
  4362.                mov   ax,4c00h               ; Load no. of DOS Exit function
  4363.                                             ;   in AH, and 0 exit code in AL
  4364.                int   21h                    ; Call interrupt 21H (DOS)
  4365.  
  4366.                END
  4367.  
  4368.    A tiny-model program could be produced by simply taking the small-model
  4369.    version from earlier in the chapter, and changing the first line to the
  4370.    following:
  4371.  
  4372.                .MODEL tiny
  4373.  
  4374.    The code would then run correctly. However, the sample code in this
  4375.    section takes advantage of tiny model by eliminating the stack segment.
  4376.    DOS initializes the SS (Stack Segment) register and SP (Stack Pointer)
  4377.    register for you, so you need not declare a stack. The assembler ignores
  4378.    stack segments in tiny model.
  4379.  
  4380.    The program still includes the .STARTUP directive. With tiny model, all
  4381.    this directive does is generate the statement ORG 100h.
  4382.  
  4383.    ──────────────────────────────────────────────────────────────────────────
  4384.    NOTE   The statement ORG 100h is necessary for programs in the .COM
  4385.    format, and must appear just before the first line of executable code. ORG
  4386.    100h starts the location counter at 100 hexadecimal, reflecting the way
  4387.    that DOS loads .COM files into memory. (DOS reserves the first 256 bytes
  4388.    for the Program Segment Prefix (PSP).) See Section 6.6, "Setting the
  4389.    Location Counter," for more information on the ORG directive.
  4390.    ──────────────────────────────────────────────────────────────────────────
  4391.  
  4392.    With tiny-model programs, QuickAssembler lets you define separate code and
  4393.    data segments, but combines these segments into a single physical segment,
  4394.    called a "group." QuickAssembler places the code segment first regardless
  4395.    of how you write your source code. The resulting .COM file assumes a
  4396.    single segment address for the whole program (as required by the structure
  4397.    of a .COM file), and execution automatically begins at the proper address.
  4398.    Finally, Quick-Assembler directs the linker to output a file in the .COM
  4399.    format rather than the .EXE format.
  4400.  
  4401.    ──────────────────────────────────────────────────────────────────────────
  4402.    NOTE  "Groups" are a standard concept in 8086 assembly language. You can
  4403.    place a series of segments into a group. The total size must not exceed
  4404.    64K. The linker responds by combining all the segments into a single
  4405.    physical segment in which all addresses share the same segment address.
  4406.    For a fuller explanation of groups and segments, see Chapter 5.
  4407.    ──────────────────────────────────────────────────────────────────────────
  4408.  
  4409.    When you write .COM files, you must observe some important restrictions.
  4410.    You cannot use program-defined segment addresses. Similarly, you have no
  4411.    access to defined segment addresses, such as @data and @code.
  4412.  
  4413.    Because .COM files lack relocation-table entries, DOS cannot adjust
  4414.    segment addresses at load time. The program must use absolute segment
  4415.    addresses or else assume the loading segment address that DOS assigns. The
  4416.    principal restriction is that you cannot refer to program-defined segment
  4417.    addresses. Therefore, memory references can be of three kinds:
  4418.  
  4419.    1. Any memory location within the 64K program area. For these memory
  4420.       references, you do not load a new value into any of the segment
  4421.       registers.
  4422.  
  4423.    2. Hard-coded locations in memory that have special meaning at the system
  4424.       or hardware level. A video-page address, such as B800:0000, is such a
  4425.       special segment address.
  4426.  
  4427.    3. An address returned to you by a DOS or ROM-BIOS function. For example,
  4428.       DOS function 48H, Allocate Memory, returns a pointer to a block of
  4429.       dynamically allocated memory.
  4430.  
  4431.  
  4432.  4.9  Creating .COM Files with Full Segment Definitions
  4433.  
  4434.    You don't generally need to use full segment definitions to create .COM
  4435.    files. However, when you do use these directives with programs written in
  4436.    .COM format, you need to follow certain rules. The assembler automatically
  4437.    follows most of these rules when you use simplified segment directives.
  4438.  
  4439.    The guidelines for .COM format are listed below:
  4440.  
  4441.    ■  Place the entire program into one physical segment. It's possible to
  4442.       divide your program into separate logical segments, then group them
  4443.       into one physical segment with the GROUP directive. Simplified segment
  4444.       directives, in fact, use this technique with tiny model.
  4445.  
  4446.       However, you must ensure that code, not data, appears at the beginning
  4447.       of the .COM file. A number of different factors affect segment
  4448.       ordering, so it may be hard to ensure that the code segment appears
  4449.       first. Thus, creating just one segment is the more reliable method.
  4450.  
  4451.       In contrast, when you use simplified segment directives with tiny
  4452.       model, the assembler always places the code segment at the beginning of
  4453.       the .COM file.
  4454.  
  4455.    ■  Use the ASSUME directive to inform the assembler that all segment
  4456.       registers will point to the beginning of the segment. At load time, DOS
  4457.       sets all segment registers to this address. The ASSUME directive
  4458.       informs the assembler of this fact so that it can correctly calculate
  4459.       offset addresses. This directive is not necessary when you use
  4460.       simplified segment directives.
  4461.  
  4462.    ■  Use the ORG directive to set the location counter. At load time, DOS
  4463.       sets the starting address to 100H. The first 100H bytes are reserved
  4464.       for the Program Segment Prefix (PSP). The statement ORG 100h is
  4465.       necessary for the assembler to assign addresses in a way consistent
  4466.       with run-time conditions. Otherwise, jump instructions and data
  4467.       references will be wrong.
  4468.  
  4469.       When you use simplified segments directives with tiny model, the
  4470.       assembler automatically sets the location counter to 100H.
  4471.  
  4472.    ■  Use the END statement to take one argument: a starting address. This
  4473.       argument is not necessary if you use the .STARTUP simplified segment
  4474.       directive, because the program automatically begins execution wherever
  4475.       you place .STARTUP.
  4476.  
  4477.    The modified procedure is shown below:
  4478.  
  4479.    _TEXT       SEGMENT 'CODE'                 ; Define code segment
  4480.                ASSUME  cs:_TEXT,ds:_TEXT,ss:_TEXT
  4481.                ORG     100h
  4482.    start:      jmp     begin
  4483.  
  4484.    message     DB      "Hello, world.",13,10  ; Message to print
  4485.    lmessage    EQU     $ - message            ; Determine length of message
  4486.    begin:      mov     bx,1                   ; Load 1 - file handle
  4487.                                               ;   for standard output
  4488.                mov     cx,lmessage            ; Load length of message
  4489.                mov     dx,OFFSET message      ; Load address of message
  4490.                mov     ah,40h                 ; Load no. of DOS Write function
  4491.                int     21h                    ; Call interrupt 21H (DOS)
  4492.  
  4493.                mov     ax,4c00h               ; Load no. of DOS Exit function
  4494.                                               ;   in AH, and 0 exit code in AL
  4495.                int     21h                    ; Call interrupt 21H (DOS)
  4496.  
  4497.    _TEXT       ENDS
  4498.                END     start
  4499.  
  4500.    The first three statements are new. The SEGMENT statement defines the
  4501.    beginning of a segment named _TEXT. (Instead of using the name _TEXT, you
  4502.    can choose any other valid symbolic name.) The ASSUME statement then
  4503.    informs the assembler that the CS, DS, and SS segment registers will all
  4504.    point to the beginning of this segment at run time. Finally, the ORG
  4505.    statement informs the assembler that the instruction pointer will be set
  4506.    to 100H.
  4507.  
  4508.    _TEXT       SEGMENT                        ; Define code segment
  4509.                ASSUME  cs:_TEXT,ds:_TEXT,ss:_TEXT
  4510.                ORG     100h
  4511.  
  4512.    The body of the procedure now includes code and data together in the same
  4513.    segment. The first item in the segment must be an instruction, because
  4514.    .COM files always begin execution at the start of the file. Attempting to
  4515.    execute data would almost certainly cause program failure. Since there is
  4516.    no separate data segment, the first instruction jumps around the data
  4517.    declarations.
  4518.  
  4519.    start:      jmp     begin
  4520.  
  4521.    message     DB      "Hello, world.",13,10  ; Message to print
  4522.    lmessage    EQU     $ - message            ; Determine length of message
  4523.    begin:      mov     bx,1                   ; Load 1 - file handle for
  4524.                                               ;   standard output
  4525.  
  4526.    Another way to write a program for .COM format is to place data
  4527.    declarations after the end of the instructions. However, the assembler
  4528.    often produces better results if you place data declarations early in the
  4529.    source file. That way, you avoid forward references to data.
  4530.  
  4531.    The source file ends by giving an argument to the END statement. This
  4532.    statement is necessary because the program does not use the .STARTUP
  4533.    directive. The argument to END must be the label of the first instruction
  4534.    executed:
  4535.  
  4536.                END     start
  4537.  
  4538.  
  4539.  
  4540.  ────────────────────────────────────────────────────────────────────────────
  4541.  PART 2:  Using Directives
  4542.  
  4543.  
  4544.    Part 2 of the Programmer's Guide (comprising Chapters 5-12) describes
  4545.    the directives and operators recognized by the Microsoft QuickAssembler.
  4546.    Directives are nonexecutable statements that give general information to
  4547.    the assembler. Some of the more important directives declare program
  4548.    structure, define data, and create macros. Operators indicate calculations
  4549.    to be performed at assembly time.
  4550.  
  4551.    Chapters 5-8 present the basic directives you need to write a program,
  4552.    including segment, data, multimodule, and structure directives. Chapter
  4553.    9 deals specifically with operators. Chapter 10 describes conditional
  4554.    assembly, and Chapter 11 presents macros, a technique for replacing a
  4555.    series of frequently used instructions with a single statement. The
  4556.    directives that control your output are covered in Chapter 12.
  4557.  
  4558.  
  4559.  
  4560.  
  4561.  ────────────────────────────────────────────────────────────────────────────
  4562.  Chapter 5:  Defining Segment Structure
  4563.  
  4564.  
  4565.    A segment is an area in memory up to 64K in size, in which all locations
  4566.    share the same segment address. The 8086 assembly-language modules use
  4567.    segments for two reasons:
  4568.  
  4569.    ■  Segments provide a convenient means for dividing a program into its
  4570.       major divisions──code, data, constant data, and stack.
  4571.  
  4572.    ■  The architecture of the 8086 requires some use of segments. Every
  4573.       reference to memory must be relative to one of the four segment
  4574.       registers, as described in Section 2.7, "Segmented Addressing and
  4575.       Segment Registers." Segment definitions make it possible for
  4576.       QuickAssembler to assume the use of the same segment register for a
  4577.       large number of different addresses.
  4578.  
  4579.    You can define segments by using simplified segment directives or full
  4580.    segment definitions.
  4581.  
  4582.    In most cases, simplified segment directives are a better choice. They are
  4583.    easier to use and more consistent, yet you seldom sacrifice any
  4584.    functionality by using them. Simplified segment directives automatically
  4585.    define the segment structure required when combining assembler modules
  4586.    with modules prepared with Microsoft high-level languages.
  4587.  
  4588.    Although more difficult to use, full segment definitions give more
  4589.    complete control over segments. A few complex programs may require full
  4590.    segment definitions in order to get unusual segment orders and types.
  4591.  
  4592.    This chapter describes both methods. If you choose to use simplified
  4593.    segment directives, you will probably not need to read about full segment
  4594.    definitions.
  4595.  
  4596.  
  4597.  5.1  Simplified Segment Directives
  4598.  
  4599.    Simplified segment directives provide an easy way to write
  4600.    assembly-language programs. They handle some of the difficult aspects of
  4601.    segment definition automatically, and assume the same conventions adopted
  4602.    by Microsoft high-level languages.
  4603.  
  4604.    When you write stand-alone assembler programs, the simplified segment
  4605.    directives make programming easier. The Microsoft conventions are flexible
  4606.    enough to work for most kinds of programs.
  4607.  
  4608.    When you write assembler routines to be linked with Microsoft high-level
  4609.    languages, the simplified segment directives ensure against mistakes that
  4610.    would make your modules incompatible. The names are automatically defined
  4611.    consistently and correctly.
  4612.  
  4613.    The simplified segment directives automatically generate the same ASSUME
  4614.    and GROUP statements used by Microsoft high-level languages. You can learn
  4615.    more about the ASSUME and GROUP directives in Sections 5.3 and 5.4.
  4616.  
  4617.    However, for most programs you do not need to understand these directives.
  4618.    Simply use the simplified segment directives in the format shown in the
  4619.    examples.
  4620.  
  4621.  
  4622.  5.1.1  Understanding Memory Models
  4623.  
  4624.    To use simplified segment directives, you must declare a memory model for
  4625.    your program. The memory model specifies the default size of data and code
  4626.    used in a program.
  4627.  
  4628.    Microsoft high-level languages require that each program have a default
  4629.    size (or memory model). Any assembly-language routine called from a
  4630.    high-level language program should have the same memory model as the
  4631.    calling program. The C compiler provided with QuickAssembler supports all
  4632.    models except tiny. If you use assembly modules with a different compiler,
  4633.    the compiler documentation should tell what memory models are supported.
  4634.  
  4635.    The most commonly used memory models are described below:
  4636.  
  4637.    Model               Description
  4638.    ──────────────────────────────────────────────────────────────────────────
  4639.    Tiny                All data and code fit in a single physical segment
  4640.                        (group). Tiny-model programs can be converted to
  4641.                        .COM-file format with the Generate COM File option in
  4642.                        the Linker Flags dialog box (or the linker /TINY
  4643.                        option used with QCL). Tiny-model programs have
  4644.                        restrictions described in Chapter 4, "Writing
  4645.                        Stand-Alone Assembly Programs."
  4646.  
  4647.    Small               All data fits within a single 64K segment, and all
  4648.                        code fits within a 64K segment. Therefore, all code
  4649.                        and data can be accessed as near. This is the most
  4650.                        common model for stand-alone assembler programs. C is
  4651.                        the only Microsoft language that supports this model.
  4652.  
  4653.    Medium              All data fits within a single 64K segment, but code
  4654.                        may be greater than 64K. Therefore, data is near, but
  4655.                        code is far. Most recent versions of Microsoft
  4656.                        high-level languages support this model.
  4657.  
  4658.    Compact             All code fits within a single 64K segment, but the
  4659.                        total amount of data may be greater than 64K (although
  4660.                        no array can be larger than 64K). Therefore, code is
  4661.                        near, but data is far. C is the only Microsoft
  4662.                        high-level language that supports this model.
  4663.  
  4664.    Large               Both code and data may be greater than 64K (although
  4665.                        no array can be larger than 64K). Therefore, both code
  4666.                        and data are far. All Microsoft high-level languages
  4667.                        support this model.
  4668.  
  4669.    Huge                Both code and data may be greater than 64K. In
  4670.                        addition, any individual data array can be larger than
  4671.                        64K. From the standpoint of QuickAssembler, this
  4672.                        memory model is almost equivalent to large model (the
  4673.                        only exception is the meaning of the predefined equate
  4674.                        @DataSize). If you want to support arrays larger than
  4675.                        64K, you must provide the program logic to support
  4676.                        these arrays.
  4677.  
  4678.  
  4679.    Stand-alone assembler programs can have any model. Tiny and small model
  4680.    are adequate for most programs written entirely in assembly language.
  4681.    Since near data or code can be accessed more quickly, the smallest memory
  4682.    model that can accommodate your code and data is usually the most
  4683.    efficient.
  4684.  
  4685.    Mixed-model programs use the default size for most code and data but
  4686.    override the default for particular data items. Stand-alone assembler
  4687.    programs can be written as mixed-model programs by making specific
  4688.    procedures or variables near or far. Some Microsoft high-level languages
  4689.    have NEAR, FAR, and HUGE keywords that enable you to override the default
  4690.    size of individual data or code items.
  4691.  
  4692.  
  4693.  5.1.2  Specifying DOS Segment Order
  4694.  
  4695.    The DOSSEG directive specifies that segments be ordered according to the
  4696.    DOS segment-order convention. This is the convention used by Microsoft
  4697.    high-level-language compilers.
  4698.  
  4699.    Syntax
  4700.  
  4701.    DOSSEG
  4702.  
  4703.    Using the DOSSEG directive enables you to maintain a consistent, logical
  4704.    segment order without actually defining segments in that order in your
  4705.    source file. Without this directive, the final segment order of the
  4706.    executable file depends on a variety of factors, such as segment order,
  4707.    class name, and order of linking. These factors are described in Section
  4708.    5.2, "Full Segment Definitions."
  4709.  
  4710.    Since segment order is not crucial to the proper functioning of most
  4711.    stand-alone assembler programs, you can simply use the DOSSEG directive
  4712.    and ignore the whole issue of segment order.
  4713.  
  4714.    ──────────────────────────────────────────────────────────────────────────
  4715.    NOTE  Using the DOSSEG directive (or the /DOSSEG linker option) has two
  4716.    side effects. The linker generates symbols called _end and _edata. You
  4717.    should not use these names in programs that contain the DOSSEG directive.
  4718.    Also, the linker increases the offset of the first byte of the code
  4719.    segment by 16 bytes in small and compact models. This is to give proper
  4720.    alignment to executable files created with Microsoft compilers.
  4721.    ──────────────────────────────────────────────────────────────────────────
  4722.  
  4723.    If you want to use the DOS segment-order convention in stand-alone
  4724.    assembler programs, you should use the DOSSEG argument in the main module.
  4725.    Modules called from the main module need not use the DOSSEG directive.
  4726.  
  4727.    You do not need to use the DOSSEG directive for modules called from
  4728.    Microsoft high-level languages, since the compiler already defines DOS
  4729.    segment order.
  4730.  
  4731.    Under the DOS segment-order convention, segments have the following order:
  4732.  
  4733.    1. All segment names having the class name 'CODE'
  4734.  
  4735.    2. Any segments that do not have class name 'CODE' and are not part of the
  4736.       group DGROUP
  4737.  
  4738.    3. Segments that are part of DGROUP, in the following order:
  4739.  
  4740.       a. Any segments of class BEGDATA (this class name is reserved for
  4741.          Microsoft use)
  4742.  
  4743.       b. Any segments not of class BEGDATA, BSS, or STACK
  4744.  
  4745.       c. Segments of class BSS
  4746.  
  4747.       d. Segments of class STACK
  4748.  
  4749.    Using the DOSSEG directive has the same effect as using the /DOSSEG linker
  4750.    option.
  4751.  
  4752.    The directive works by writing to the comment record of the object file.
  4753.    The Intel(R) title for this record is COMENT. If the linker detects a
  4754.    certain sequence of bytes in this record, it automatically puts segments
  4755.    in the DOS order.
  4756.  
  4757.  
  4758.  5.1.3  Defining Basic Attributes of the Module
  4759.  
  4760.    The .MODEL directive defines attributes that affect the entire module:
  4761.    memory model, default calling and naming conventions, and stack type. This
  4762.    directive should appear before any other simplified segment directive.
  4763.  
  4764.    Syntax
  4765.  
  4766.    .MODEL memorymodel[[[[,language]],stacktype]]
  4767.  
  4768.    Each of the three fields defines a basic attribute. The memorymodel field
  4769.    defines the segment structure of the module. The language field defines
  4770.    the default calling and naming conventions assumed by PROC statements.
  4771.    These conventions correspond to the high-level language you specify. The
  4772.    stacktype field determines whether or not the assembler assumes that the
  4773.    SS register is equal to the DS register.
  4774.  
  4775.    The memorymodel field can be TINY, SMALL, MEDIUM, COMPACT, LARGE, or HUGE.
  4776.    The assembler defines segments the same way for large and huge models, but
  4777.    the @DataSize equate (explained in Section 5.1.5, "Using Predefined
  4778.    Segment Equates") gives a different value for these two models.
  4779.  
  4780.    If you write an assembler routine for a high-level language, the
  4781.    memorymodel field should match the memory model used by the compiler or
  4782.    interpreter. If you write a stand-alone assembler program, you can use any
  4783.    model. Section 5.1.1 describes each memory model.
  4784.  
  4785.    The optional language field tells the assembler to follow the naming,
  4786.    calling, and return conventions appropriate to the indicated language. In
  4787.    addition, if you use the language argument, the assembler automatically
  4788.    makes all procedure names public. You can use C, Pascal, FORTRAN, or BASIC
  4789.    as the language argument. The last three are equivalent, since these
  4790.    languages share the same naming and calling conventions.
  4791.  
  4792.    Note that although the language field is optional, you will not be able to
  4793.    use the high-level language features of the PROC directive if you do not
  4794.    give it. Normally, you should specify a language with .MODEL. If you use C
  4795.    for the language argument, all public and external names are by default
  4796.    prefixed with an underscore (_) in the .OBJ file. Specifying any other
  4797.    language has no effect on the names.
  4798.  
  4799.    ──────────────────────────────────────────────────────────────────────────
  4800.    NOTE  The assembler does not truncate names in order to match the
  4801.    conventions of specific languages, such as FORTRAN or Pascal. Moreover,
  4802.    using the C type specifier does not cause the assembler to preserve case.
  4803.    To preserve lowercase names in public symbols, choose one of the assembler
  4804.    flags that preserves case (Preserve Extrn or Preserve Case), or assemble
  4805.    with /Cx or /Cl on the QCL command line. Within the environment, the
  4806.    Preserve Extrn flag is on by default.
  4807.    ──────────────────────────────────────────────────────────────────────────
  4808.  
  4809.    See Appendix A for an explanation of how the different calling
  4810.    conventions are implemented. You should also note that each language has
  4811.    different defaults for passing parameters by value or by reference.
  4812.    Depending on which method is used, a high-level language passes a
  4813.    parameter either as a value or as a pointer to the value.
  4814.  
  4815.    The optional stacktype field determines whether or not the assembler
  4816.    assumes that SS is equal to DS. The default value is nearStack, which
  4817.    assumes that SS is part of the default data area, so that SS is equal to
  4818.    DS, and SP is set to the top of the data area. You can also use farStack,
  4819.    which assumes that the stack segment is in a separate physical segment
  4820.    from the default data area.
  4821.  
  4822.    If you write a module called from QuickC, you should always use the
  4823.    default (in other words, just leave the field blank), since QuickC always
  4824.    assumes DS equals SS. If you write modules for a compiler (such as the
  4825.    Microsoft Optimized C Compiler) that supports customized memory models,
  4826.    use farStack for models in which SS does not equal DS. If you write a
  4827.    stand-alone assembler program, you can choose either setting. If you use
  4828.    the .STARTUP directive, the assembler automatically generates the proper
  4829.    code for setting up the indicated stack type.
  4830.  
  4831.    If you write a stand-alone module without using .STARTUP, you should
  4832.    exercise caution. If you initialize DS but do not adjust SS and SP (as
  4833.    described in Section 5.5.3, "Initializing the SS and SP Registers), use
  4834.    the farStack keyword. If you do adjust SS and SP as described in Section
  4835.    5.5.3, you can use the default value, nearStack.
  4836.  
  4837.    Example 1
  4838.  
  4839.                DOSSEG
  4840.                .MODEL  small,c
  4841.  
  4842.    This statement defines default segments for small-model programs and
  4843.    creates the ASSUME and GROUP statements used by small-model programs. The
  4844.    segments are automatically ordered according to the Microsoft convention.
  4845.    The example statements might be used at the start of the main (or only)
  4846.    module of a stand-alone assembler program.
  4847.  
  4848.    Example 2
  4849.  
  4850.                .MODEL  large,pascal
  4851.  
  4852.    This statement defines default segments for large-model programs and
  4853.    creates the ASSUME and GROUP statements used by large-model programs. It
  4854.    does not automatically order segments according to the Microsoft
  4855.    convention. The example statement might be used at the start of an
  4856.    assembly module that would be called from a large-model Pascal program or
  4857.    a C program in which the Pascal calling convention was specified.
  4858.  
  4859.    Example 3
  4860.  
  4861.                .MODEL  small,c,farStack
  4862.  
  4863.    This statement defines default segments for a small-model program and
  4864.    creates the appropriate ASSUME and GROUP statements. In addition, this
  4865.    statement makes all procedures public, and directs the assembler to prefix
  4866.    an underscore to the beginning of each public name, so that the naming
  4867.    convention is compatible with C. If you later use the PROC statement to
  4868.    declare parameters, the assembler will assume that the parameters are
  4869.    placed on the stack in the order specified by the C calling convention. In
  4870.    addition, the statement uses farStack, indicating that SS is not equal to
  4871.    DS.
  4872.  
  4873.    The last example would be appropriate for a module called by a C module
  4874.    with a customized memory model, compiled with a setting that did not
  4875.    assume SS equal to DS. Note that QuickC does not support customized memory
  4876.    models.
  4877.  
  4878.    ──────────────────────────────────────────────────────────────────────────
  4879.    NOTE  The assembler does not normally display the code generated by the
  4880.    high-level-language support features. You can see the code produced by
  4881.    these features by using the .LALL directive or the /LA command-line
  4882.    option.
  4883.    ──────────────────────────────────────────────────────────────────────────
  4884.  
  4885.    To write procedures for use with more than one language and memory model,
  4886.    you can use text macros for the memory model and language arguments, and
  4887.    define the values from the command line or in the Assembler Flags dialog
  4888.    box. For example, the following .MODEL directive uses text macros for the
  4889.    memorymodel and language arguments:
  4890.  
  4891.    %           .MODEL memmodel,lang  ; Use % to evaluate memmodel, lang
  4892.  
  4893.    The values of the two text macros can be defined from the command line
  4894.    using the /D switch:
  4895.  
  4896.    QCL /Dmemmodel=MEDIUM /Dlang=C /AM /Cx main.c proc.asm
  4897.  
  4898.  
  4899.  5.1.4  Defining Simplified Segments
  4900.  
  4901.    Each of the directives .CODE, .STACK, .DATA, .DATA?, .CONST, .FARDATA,
  4902.    .FARDATA?, and .STARTUP indicate the start of a segment. They also end the
  4903.    immediately preceding segment definition.
  4904.  
  4905.    Syntax
  4906.  
  4907.    .CODE [[name]]       Code segment
  4908.    .STACK [[size]]      Stack segment
  4909.    .DATA                Initialized near-data segment
  4910.    .DATA?               Uninitialized near-data segment
  4911.    .CONST               Constant-data segment
  4912.    .FARDATA [[name]]    Initialized far-data segment
  4913.    .FARDATA? [[name]]   Uninitialized far-data segment
  4914.    .STARTUP             Code to initialize segment registers
  4915.  
  4916.    For segments that take an optional name, the base file name of the source
  4917.    module is used if you do not specify a value yourself.
  4918.  
  4919.    Each new segment directive ends the previous segment. The END directive
  4920.    closes the last segment in the source file.
  4921.  
  4922.  
  4923.  5.1.4.1  How to Use Simplified Segments
  4924.  
  4925.    The .CODE, .DATA, and .STACK directives create the three basic segments
  4926.    that programs generally need to have. Chapter 4, "Writing Stand-Alone
  4927.    Assembly Programs," demonstrates how to use these directives to write
  4928.    code, data, and stack segments. Chapter 4 also explains the purpose of
  4929.    each of these segments.
  4930.  
  4931.    The .STARTUP directive initializes segment registers to the appropriate
  4932.    segment values. Chapter 4 describes the use of .STARTUP, and Section
  4933.    5.5 tells more about how .STARTUP works and what code it generates.
  4934.  
  4935.    When you write a mixed-language program, you generally don't need to
  4936.    declare a stack segment, because the start-up code in the C main module
  4937.    creates a stack for you. When you write a stand-alone program, you should
  4938.    declare a stack segment in the main module only.
  4939.  
  4940.    Your programs can also use the .DATA? and .CONST directives to create
  4941.    segments for uninitialized and constant data, respectively. With
  4942.    stand-alone assembler programs, the use of these directives is optional,
  4943.    because you can place all data in the segment defined by .DATA if you
  4944.    want. With mixed-language programs, use .DATA? and .CONST to ensure
  4945.    compatibility with the way C handles uninitialized and constant data. Once
  4946.    you define these segments, it is up to you to place the appropriate data
  4947.    in each segment.
  4948.  
  4949.    If your program is written in compact, large, or huge model, you can use
  4950.    the .FARDATA and .FARDATA? directives to define additional data segments.
  4951.    All the data in the other data segments (defined by .DATA, .DATA?, and
  4952.    .CONST) must not exceed a total of 64K across all modules. In addition,
  4953.    the stack segment is also placed into this 64K area unless you specify
  4954.    farStack with the .MODEL directive.
  4955.  
  4956.    Data in the .FARDATA and .FARDATA? segments takes slightly longer to
  4957.    access. However, there is generally much more room in these segments for
  4958.    data definitions. For each module, the .FARDATA and .FARDATA? directives
  4959.    each create a separate physical segment that can be up to 64K in size. The
  4960.    recommended procedure is to use .FARDATA for initialized data, and
  4961.    .FARDATA? for uninitialized data, although this is optional.
  4962.  
  4963.    With medium, large, and huge model, you can use the name attribute to
  4964.    create multiple code segments within a source module. With compact, large,
  4965.    and huge model, you can also use the name attribute to create multiple
  4966.    far-data segments.
  4967.  
  4968.    Example 1
  4969.  
  4970.                DOSSEG
  4971.                .MODEL  small,c
  4972.                .STACK  100h
  4973.                .DATA
  4974.    ivariable   DB      5
  4975.    iarray      DW      50 DUP (5)
  4976.    string      DB      "This is a string"
  4977.    uarray      DW      50 DUP (?)
  4978.                EXTRN   xvariable:WORD
  4979.                .CODE
  4980.                .STARTUP
  4981.                EXTRN   xprocedure:NEAR
  4982.                call    xprocedure
  4983.                .
  4984.                .
  4985.                .
  4986.                END
  4987.  
  4988.    This code uses simplified segment directives for a small-model,
  4989.    stand-alone assembler program. Notice that initialized data, uninitialized
  4990.    data, and a string constant are all defined in the same data segment. See
  4991.    Section 5.1.7, "Default Segment Names," for an equivalent version that
  4992.    uses full segment definitions.
  4993.  
  4994.    Example 2
  4995.  
  4996.                .MODEL, large,c
  4997.                .FARDATA?
  4998.    fuarray     DW      10 DUP (?)         ; Far uninitialized data
  4999.                .CONST
  5000.    string      DB      "This is a string" ; String constant
  5001.                .DATA
  5002.    niarray     DB      100 DUP (5)        ; Near initialized data
  5003.                .FARDATA
  5004.                EXTRN   xvariable:FAR
  5005.    fiarray     DW      100 DUP (10)       ; Far initialized data
  5006.                .CODE   TASK
  5007.                EXTRN   xprocedure:PROC
  5008.    task        PROC
  5009.                .
  5010.                .
  5011.                .
  5012.                ret
  5013.    task        ENDP
  5014.                END
  5015.  
  5016.    This example uses simplified segment directives to create a module that
  5017.    might be called from a large-model, high-level-language program. Notice
  5018.    that different types of data are put in different segments to conform to
  5019.    Microsoft compiler conventions. See Section 5.1.7, "Default Segment
  5020.    Names," for an equivalent version using full segment definitions.
  5021.  
  5022.  
  5023.  5.1.4.2  How Simplified Segments Are Implemented
  5024.  
  5025.    When you use the simplified segment directives described above, the
  5026.    assembler defines segments in a way compatible with Microsoft high-level
  5027.    languages.
  5028.  
  5029.    This section makes a number of references to groups and ASSUME statements.
  5030.    Both of these concepts arise from the need to deal with the 8086 segmented
  5031.    architecture. A "group" consists of one or more segments, totaling no more
  5032.    than 64K. When multiple segments are placed into a group, the linker
  5033.    combines these segments into a single physical segment. All addresses in
  5034.    the physical segment are adjusted so that they share the same segment
  5035.    address. Use of groups is convenient because it removes the need to
  5036.    constantly reload the DS register.
  5037.  
  5038.    The ASSUME directive is described at greater length in Section 5.4,
  5039.    "Associating Segments with Registers." This directive informs the
  5040.    assembler where a segment register will point to at run time so that the
  5041.    assembler can correctly calculate offset addresses relative to the value
  5042.    in the appropriate segment register.
  5043.  
  5044.    Unless you use tiny model, the code segment (defined with .CODE) is placed
  5045.    in its own physical segment, separate from all the data and stack
  5046.    segments. With medium, large, or huge model, you can define multiple code
  5047.    segments within one source model by using .CODE repeatedly, each time with
  5048.    a different name attribute. When you use this technique, each .CODE
  5049.    directive generates a new ASSUME statement so that the assembler knows
  5050.    where CS points to at run time.
  5051.  
  5052.    Segments defined with the .STACK, .CONST, .DATA, or .DATA? directives are
  5053.    placed in a group called DGROUP. Segments defined with the .FARDATA or
  5054.    .FARDATA? directives are not placed in any group. See Section 5.3 for
  5055.    more information on segment groups. When initializing the DS register to
  5056.    access data in a group-associated segment, the value of DGROUP should be
  5057.    loaded into DS. The .STARTUP directive does this initialization
  5058.    automatically.
  5059.  
  5060.    The .MODEL directive generates ASSUME statements to inform the assembler
  5061.    that at run time, DS, SS, and ES will all point to the beginning of
  5062.    DGROUP. You don't need to write these ASSUME statements yourself.
  5063.  
  5064.    If you specify farStack with the .MODEL directive, the stack is placed in
  5065.    a separate physical segment and the .MODEL directive generates an ASSUME
  5066.    statement to inform the assembler that SS does not point to the same
  5067.    segment address that DS does.
  5068.  
  5069.  
  5070.  5.1.5  Using Predefined Segment Equates
  5071.  
  5072.    Several equates are predefined for you. You can use the equate names at
  5073.    any point in your code to represent the equate values. You should not
  5074.    assign equates having these names. The predefined equates are listed
  5075.    below:
  5076.  
  5077.    Name                Value
  5078.    ──────────────────────────────────────────────────────────────────────────
  5079.    @CodeSize and       If the .MODEL directive has been used, the value of
  5080.    @DataSize           @CodeSize is 0 for the models that use near-code
  5081.                        labels (tiny, small, and compact) or 1 for models that
  5082.                        use far-code labels (medium, large, and huge). The
  5083.                        value of @DataSize is 0 for models that use near-data
  5084.                        labels (tiny, small, and medium), 1 for compact and
  5085.                        large models, and 2 for huge models. These values can
  5086.                        be used in conditional-assembly statements.
  5087.  
  5088.                IF      @DataSize
  5089.                les     bx,pointer             ; Load far pointer
  5090.                mov     ax,es:WORD PTR [bx]
  5091.                ELSE
  5092.                mov     bx,WORD PTR pointer    ; Load near pointer
  5093.                mov     ax,WORD PTR [bx]
  5094.                ENDIF
  5095.  
  5096.    @CurSeg             This name has the segment name of the current segment.
  5097.                        This value may be convenient for ASSUME statements,
  5098.                        segment overrides, or other cases in which you need to
  5099.                        access the current segment. It can also be used to end
  5100.                        a segment.
  5101.  
  5102.    @FileName           This value represents the base name of the current
  5103.                        source file. For example, if the current source file
  5104.                        is TASK.ASM, the value of @FileName is TASK. This
  5105.                        value can be used in any name you would like to change
  5106.                        if the file name changes. For example, it can be used
  5107.                        as a procedure name:
  5108.  
  5109.  
  5110.    @FileName   PROC
  5111.                .
  5112.                .
  5113.                .
  5114.    @FileName   ENDP
  5115.  
  5116.    @Model              As with the @CodeSize and @DataSize predefined
  5117.                        equates, you must first use the .MODEL directive
  5118.                        before using the @Model equate. The value of @Model is
  5119.                        1 for tiny model, 2 for small, 3 for compact, 4 for
  5120.                        medium, 5 for large, and 6 for huge. @Model can be
  5121.                        used in conditional-assembly statements.
  5122.  
  5123.    Segment equates     For each of the primary segment directives, there is a
  5124.                        corresponding equate with the same name, except that
  5125.                        the equate starts with an "at sign" (@) instead of a
  5126.                        period. For example, the @code equate represents the
  5127.                        segment name defined by the .CODE directive.
  5128.                        Similarly, @fardata represents the .FARDATA segment
  5129.                        name and @fardata? represents the .FARDATA? segment
  5130.                        name. The @data equate represents the group name
  5131.                        shared by all the near-data segments. It can be used
  5132.                        to access the segments created by the .DATA, .DATA?,
  5133.                        .CONST, and .STACK segments.
  5134.  
  5135.                        These equates can be used in ASSUME statements and at
  5136.                        any other time a segment must be referred to by name.
  5137.  
  5138.  
  5139.    ──────────────────────────────────────────────────────────────────────────
  5140.    NOTE  Although predefined equates are part of the simplified segment
  5141.    system, the @CurSeg and @FileName equates are also available when using
  5142.    full segment definitions. If you use the /Cl option or set Preserve Case
  5143.    in the Assembler Flags dialog box, predefined equates will be case
  5144.    sensitive with the exact names shown above.
  5145.    ──────────────────────────────────────────────────────────────────────────
  5146.  
  5147.  
  5148.  5.1.6  Simplified Segment Defaults
  5149.  
  5150.    Although your program can combine full segment definitions and simplified
  5151.    segment directives, the .MODEL directive enables certain features of
  5152.    simplified segment directives that change defaults. Defaults that change
  5153.    are listed below:
  5154.  
  5155.    ■  If you do not use the .MODEL directive, the default size for the PROC
  5156.       directive is always NEAR. If you use the .MODEL directive, the PROC
  5157.       directive is associated with the specified memory model: NEAR for tiny,
  5158.       small, and compact models and FAR for medium, large, and huge models.
  5159.       See Section 6.4.3, "Procedure Labels," for further discussion of the
  5160.       PROC directive.
  5161.  
  5162.    ■  If you use the .MODEL directive, the OFFSET operator returns an offset
  5163.       relative to the beginning of a group, whenever a data item is defined
  5164.       within a group. If you do not use the .MODEL directive, the OFFSET
  5165.       operator always returns an offset relative to the beginning of the
  5166.       segment. The simplified segment directives .DATA, .DATA?, and .STACK
  5167.       all create segments that are part of the group DGROUP.
  5168.  
  5169.       For example, assume the variable test1 was declared in a segment
  5170.       defined with the .DATA directive and test2 was declared in a segment
  5171.       defined with the .FARDATA directive. The statement
  5172.  
  5173.  
  5174.                      mov     ax,OFFSET test1
  5175.  
  5176.       loads the address of test1 relative to DGROUP. The statement
  5177.  
  5178.  
  5179.                      mov     ax,OFFSET test2
  5180.  
  5181.       loads the address of test2 relative to the segment defined by the
  5182.       .FARDATA directive. See Section 5.3 for more information on groups.
  5183.  
  5184.  
  5185.  5.1.7  Default Segment Names
  5186.  
  5187.    If you use the simplified segment directives by themselves, you do not
  5188.    need to know the names assigned for each segment. However, it is possible
  5189.    to mix full segment definitions with simplified segment directives.
  5190.    Therefore, some programmers may wish to know the actual names assigned to
  5191.    all segments.
  5192.  
  5193.    Table 5.1 shows the default segment names created by each directive.
  5194.  
  5195.    Table 5.1 Default Segments and Types for Standard Memory Models
  5196.  
  5197.    Model     Directive Name      Align     Combine   Class       Group
  5198.    ──────────────────────────────────────────────────────────────────────────
  5199.    Tiny      .CODE     _TEXT     WORD      PUBLIC    'CODE'      DGROUP
  5200.  
  5201.              .DATA     _DATA     WORD      PUBLIC    'DATA'      DGROUP
  5202.  
  5203.              .CONST    CONST     WORD      PUBLIC    'CONST'     DGROUP
  5204.  
  5205.              .DATA?    _BSS      WORD      PUBLIC    'BSS'       DGROUP
  5206.  
  5207.    ──────────────────────────────────────────────────────────────────────────
  5208.    Small     .CODE     _TEXT     WORD      PUBLIC    'CODE'
  5209.  
  5210.              .DATA     _DATA     WORD      PUBLIC    'DATA'      DGROUP
  5211.  
  5212.              .CONST    CONST     WORD      PUBLIC    'CONST'     DGROUP
  5213.  
  5214.              .DATA?    _BSS      WORD      PUBLIC    'BSS'       DGROUP
  5215.  
  5216.              .STACK    STACK     PARA      STACK     'STACK'     DGROUP
  5217.  
  5218.    ──────────────────────────────────────────────────────────────────────────
  5219.    Medium    .CODE     name_TEXT WORD      PUBLIC    'CODE'
  5220.  
  5221.              .DATA     _DATA     WORD      PUBLIC    'DATA'      DGROUP
  5222.  
  5223.              .CONST    CONST     WORD      PUBLIC    'CONST'     DGROUP
  5224.  
  5225.              .DATA?    _BSS      WORD      PUBLIC    'BSS'       DGROUP
  5226.  
  5227.              .STACK    STACK     PARA      STACK     'STACK'     DGROUP
  5228.  
  5229.    ──────────────────────────────────────────────────────────────────────────
  5230.    Compact   .CODE     _TEXT     WORD      PUBLIC    'CODE'
  5231.  
  5232.              .FARDATA  FAR_DATA  PARA      private   'FAR_DATA'
  5233.  
  5234.              .FARDATA? FAR_BSS   PARA      private   'FAR_BSS'
  5235.  
  5236.              .DATA     _DATA     WORD      PUBLIC    'DATA'      DGROUP
  5237.  
  5238.              .CONST    CONST     WORD      PUBLIC    'CONST'     DGROUP
  5239.  
  5240.              .DATA?    _BSS      WORD      PUBLIC    'BSS'       DGROUP
  5241.  
  5242.              .STACK    STACK     PARA      STACK     'STACK'     DGROUP
  5243.  
  5244.    ──────────────────────────────────────────────────────────────────────────
  5245.    Large or  .CODE     name_TEXT WORD      PUBLIC    'CODE'
  5246.  
  5247.    huge      .FARDATA  FAR_DATA  PARA      private   'FAR_DATA'
  5248.  
  5249.              .FARDATA? FAR_BSS   PARA      private   'FAR_BSS'
  5250.  
  5251.              .DATA     _DATA     WORD      PUBLIC    'DATA'      DGROUP
  5252.  
  5253.              .CONST    CONST     WORD      PUBLIC    'CONST'     DGROUP
  5254.  
  5255.              .DATA?    _BSS      WORD      PUBLIC    'BSS'       DGROUP
  5256.  
  5257.              .STACK    STACK     PARA      STACK     'STACK'     DGROUP
  5258.  
  5259.    ──────────────────────────────────────────────────────────────────────────
  5260.  
  5261.  
  5262.    The name used as part of far-code segment names is the file name of the
  5263.    module. The default name associated with the .CODE directive can be
  5264.    overridden in medium and large models. The default names for the .FARDATA
  5265.    and .FARDATA? directives can always be overridden.
  5266.  
  5267.    The segment and group table at the end of listings always shows the actual
  5268.    segment names. However, the GROUP and ASSUME statements generated by the
  5269.    .MODEL directive are not shown in listing files. For a program that uses
  5270.    all possible segments, group statements equivalent to the following would
  5271.    be generated:
  5272.  
  5273.    DGROUP      GROUP    _DATA,CONST,_BSS,STACK
  5274.  
  5275.    For tiny model, the following would be generated:
  5276.  
  5277.                ASSUME   cs:DGROUP,ds:DGROUP,ss:DGROUP
  5278.  
  5279.    For small and compact models, the following would be generated:
  5280.  
  5281.                ASSUME   cs:_TEXT,ds:DGROUP,ss:DGROUP
  5282.  
  5283.    For medium, large, and huge models, the following statement is given:
  5284.  
  5285.                ASSUME   cs: name_TEXT,ds:DGROUP,ss:DGROUP
  5286.  
  5287.    Example 1
  5288.  
  5289.                EXTRN   xvariable:WORD
  5290.                EXTRN   xprocedure:NEAR
  5291.    DGROUP      GROUP   _DATA,_BSS
  5292.                ASSUME  cs:_TEXT,ds:DGROUP,ss:DGROUP
  5293.    _TEXT       SEGMENT WORD PUBLIC 'CODE'
  5294.    start:      mov     ax,DGROUP                    ; Initialize data segment
  5295.                mov     ds,ax
  5296.                cli
  5297.                mov     ss,ax                        ; Move DGROUP into SS
  5298.  
  5299.                add     sp,OFFSET STACK              ; Adjust SP to top of stac
  5300.                sti
  5301.                .
  5302.                .
  5303.                .
  5304.    TEXT        ENDS
  5305.    _DATA       SEGMENT WORD PUBLIC 'DATA'
  5306.    ivariable   DB      5
  5307.    iarray      DW      50 DUP (5)
  5308.    string      DB      "This is a string"
  5309.    uarray      DW      50 DUP (?)
  5310.    _DATA       ENDS
  5311.    STACK       SEGMENT PARA STACK 'STACK'
  5312.                DB      100h DUP (?)
  5313.    STACK       ENDS
  5314.                END     start
  5315.  
  5316.    This example is equivalent to Example 1 in Section 5.1.4, "Defining
  5317.    Simplified Segments." Notice that the segment order must be different in
  5318.    this version to achieve the segment order specified by using the DOSSEG
  5319.    directive in the first Section 5.1.4 example. The external variables are
  5320.    declared at the start of the source code in this example. With simplified
  5321.    segment directives, external variables can be declared in the segment in
  5322.    which they are used. The code generated by .STARTUP is discussed in more
  5323.    detail in Section 5.5.3.
  5324.  
  5325.    Example 2
  5326.  
  5327.    DGROUP      GROUP   _DATA,CONST,STACK
  5328.                ASSUME  cs:TASK_TEXT,ds:FAR_DATA,ss:STACK
  5329.                EXTRN   xprocedure:FAR
  5330.                EXTR    xvariable:FAR
  5331.    FAR_BSS     SEGMENT PARA 'FAR_DATA'
  5332.    fuarray     DW      10 DUP (?)         ; Far uninitialized data
  5333.    FAR_BSS     ENDS
  5334.    CONST       SEGMENT WORD PUBLIC 'CONST'
  5335.    string      DB      "This is a string" ; String constant
  5336.    CONST       ENDS
  5337.    _DATA       SEGMENT WORD PUBLIC 'DATA'
  5338.    niarray     DB      100 DUP (5)        ; Near initialized data
  5339.    _DATA       ENDS
  5340.    FAR_DATA    SEGMENT WORD 'FAR_DATA'
  5341.    fiarray     DW      100 DUP (10)
  5342.    FAR_DATA    ENDS
  5343.    TASK_TEXT   SEGMENT WORD PUBLIC 'CODE'
  5344.    task        PROC    FAR
  5345.                .
  5346.                .
  5347.                .
  5348.                ret
  5349.    task        ENDP
  5350.    TASK_TEXT   ENDS
  5351.                END
  5352.  
  5353.    This example is equivalent to Example 2 in Section 5.1.4, "Defining
  5354.    Simplified Segments." Notice that the segment order is the same in both
  5355.    versions. The segment order shown here is written to the object file, but
  5356.    it is different in the executable file. The segment order specified by the
  5357.    compiler (the DOS segment order) overrides the segment order in the module
  5358.    object file.
  5359.  
  5360.  
  5361.  5.2  Full Segment Definitions
  5362.  
  5363.    If you need complete control over segments, you may want to give complete
  5364.    segment definitions. The section below explains all aspects of segment
  5365.    definitions, including how to order segments and how to define all the
  5366.    segment types.
  5367.  
  5368.  
  5369.  5.2.1  Setting the Segment-Order Method
  5370.  
  5371.    The order in which QuickAssembler writes segments to the object file can
  5372.    be either sequential or alphabetical. If the sequential method is
  5373.    specified, segments are written in the order in which they appear in the
  5374.    source code. If the alphabetical method is specified, segments are written
  5375.    in the alphabetical order of their segment names.
  5376.  
  5377.    The default is sequential. If no segment-order directive or option is
  5378.    given, segments are ordered sequentially. The segment-order method is only
  5379.    one factor in determining the final order of segments in memory. The
  5380.    DOSSEG directive (see Section 5.1.2, "Specifying DOS Segment Order") and
  5381.    class type (see Section 5.2.2.3, "Controlling Segment Structure with
  5382.    Class Type") can also affect segment order.
  5383.  
  5384.    The ordering method can be set by using the .ALPHA or .SEQ directive in
  5385.    the source code. The method can also be set using the /s (sequential) or
  5386.    /a (alphabetical) assembler options (see Appendix B, Section B.1,
  5387.    "Specifying the Segment-Order Method"). The directives have precedence
  5388.    over the options. For example, if the source code contains the .ALPHA
  5389.    directive, but the /s option is given on the command line, the segments
  5390.    are ordered alphabetically.
  5391.  
  5392.    Changing the segment order is an advanced technique. In most cases, you
  5393.    can simply leave the default sequential order in effect. If you are
  5394.    linking with high-level-language modules, the compiler automatically sets
  5395.    the segment order. The DOSSEG directive also overrides any segment-order
  5396.    directives or options.
  5397.  
  5398.    ──────────────────────────────────────────────────────────────────────────
  5399.    NOTE   Some previous versions of the IBM Macro Assembler ordered segments
  5400.    alphabetically by default. If you have trouble assembling and linking
  5401.    source-code listings from books or magazines, try using the /a option.
  5402.    Listings written for previous IBM versions of the assembler may not work
  5403.    without this option. The distinction between ENDS as the end of a segment
  5404.    and ENDS as the end of a structure is also made by the content of the
  5405.    program.
  5406.    ──────────────────────────────────────────────────────────────────────────
  5407.  
  5408.    Example 1
  5409.  
  5410.                .SEQ
  5411.    DATA        SEGMENT WORD PUBLIC 'DATA'
  5412.    DATA        ENDS
  5413.    CODE        SEGMENT WORD PUBLIC 'CODE'
  5414.    CODE        ENDS
  5415.  
  5416.    Example 2
  5417.  
  5418.                .ALPHA
  5419.    DATA        SEGMENT WORD PUBLIC 'DATA'
  5420.    DATA        ENDS
  5421.    CODE        SEGMENT WORD PUBLIC 'CODE'
  5422.    CODE        ENDS
  5423.  
  5424.    In Example 1, the DATA segment is written to the object file first because
  5425.    it appears first in the source code. In Example 2, the CODE segment is
  5426.    written to the object file first because its name comes first
  5427.    alphabetically.
  5428.  
  5429.  
  5430.  5.2.2  Defining Full Segments
  5431.  
  5432.    The beginning of a program segment is defined with the SEGMENT directive,
  5433.    and the end of the segment is defined with the ENDS directive.
  5434.  
  5435.    Syntax
  5436.  
  5437.    name SEGMENT [[align]] [[combine]] [[use]] [['class']]
  5438.    statements
  5439.    name ENDS
  5440.  
  5441.    The name defines the name of the segment. This name can be unique, or it
  5442.    can be the same name given to other segments in the program. Segments with
  5443.    identical names are treated as the same segment. For example, if it is
  5444.    convenient to put different portions of a single segment in different
  5445.    source modules, the segment is given the same name in both modules.
  5446.  
  5447.    The optional align, combine, use, and 'class' types give the linker and
  5448.    the assembler instructions on how to set up and combine segments. Types
  5449.    can be specified in any order; it is not necessary to enter all types, or
  5450.    any type, for a given segment.
  5451.  
  5452.    Defining segment types is an advanced technique. Beginning
  5453.    assembly-language programmers might try using the simplified segment
  5454.    directives discussed in Section 5.1.
  5455.  
  5456.    ──────────────────────────────────────────────────────────────────────────
  5457.    NOTE   Don't confuse the PAGE align type and the PUBLIC combine type with
  5458.    the PAGE and PUBLIC directives. The distinction should be clear from
  5459.    context since the align and combine types are only used on the same line
  5460.    as the SEGMENT directive.
  5461.    ──────────────────────────────────────────────────────────────────────────
  5462.  
  5463.  
  5464.  5.2.2.1  Controlling Alignment with Align Type
  5465.  
  5466.    The optional align type defines the range of memory addresses from which a
  5467.    starting address for the segment can be selected. The align type can be
  5468.    any one of the following:
  5469.  
  5470.    Align Type          Meaning
  5471.    ──────────────────────────────────────────────────────────────────────────
  5472.    BYTE                Uses the next available byte address
  5473.  
  5474.    WORD                Uses the next available word address (2 bytes per
  5475.                        word)
  5476.  
  5477.    DWORD               Uses the next available doubleword address (4 bytes
  5478.                        per doubleword)
  5479.  
  5480.    PARA                Uses the next available paragraph address (16 bytes
  5481.                        per paragraph)
  5482.  
  5483.    PAGE                Uses the next available page address (256 bytes per
  5484.                        page)
  5485.  
  5486.  
  5487.    If no align type is given, PARA is used by default.
  5488.  
  5489.    The linker uses the alignment information to determine the relative start
  5490.    address for each segment. DOS uses the information to calculate the actual
  5491.    start address when the program is loaded.
  5492.  
  5493.    Align types are illustrated in Figure 5.1 in the next section.
  5494.  
  5495.  
  5496.  5.2.2.2  Defining Segment Combinations with Combine Type
  5497.  
  5498.    The optional combine type defines how to combine segments having the same
  5499.    name. The combine type can be any one of the following:
  5500.  
  5501.    Combine Type        Meaning
  5502.    ──────────────────────────────────────────────────────────────────────────
  5503.    PUBLIC              Concatenates all segments having the same name to form
  5504.                        a single, contiguous segment. The total size of the
  5505.                        resulting segment is equal to the sum of all
  5506.                        contributing segments.
  5507.  
  5508.                        All instruction and data addresses in the new segment
  5509.                        are relative to a single segment register, and all
  5510.                        offsets are adjusted to represent the distance from
  5511.                        the beginning of the segment.
  5512.  
  5513.    STACK               Concatenates all segments having the same name to form
  5514.                        a single, contiguous segment. This combine type is the
  5515.                        same as the PUBLIC combine type, except that all
  5516.                        addresses in the new segment are relative to the SS
  5517.                        segment register. The total size of the resulting
  5518.                        segment is equal to the sum of all contributing
  5519.                        segments.
  5520.  
  5521.                        The Stack Pointer (SP) register is initialized to the
  5522.                        length of the segment. The stack segment of your
  5523.                        program should normally use the STACK type, since this
  5524.                        automatically initializes the SS register, as
  5525.                        described in Section 5.5.3. If you create a stack
  5526.                        segment and do not use the STACK type, you must give
  5527.                        instructions to initialize the SS and SP registers.
  5528.  
  5529.                        For each individual segment, all initialized data is
  5530.                        placed at the high end of the resulting stack segment.
  5531.                        Consequently, if more than one stack segment contains
  5532.                        initialized data, the linker overwrites this data as
  5533.                        it links in each segment. Note that stack data cannot
  5534.                        be initialized with simplified segment directives.
  5535.  
  5536.    COMMON              Creates overlapping segments by placing the start of
  5537.                        all segments having the same name at the same address.
  5538.  
  5539.                        The length of the resulting area is the length of the
  5540.                        longest segment. All addresses in the segments are
  5541.                        relative to the same base address. If variables are
  5542.                        initialized in more than one segment having the same
  5543.                        name and COMMON type, the most recently initialized
  5544.                        data replaces any previously initialized data.
  5545.  
  5546.    MEMORY              Concatenates all segments having the same name to form
  5547.                        a single, contiguous segment.
  5548.  
  5549.                        The Microsoft Overlay Linker treats MEMORY segments
  5550.                        exactly the same as PUBLIC segments. QuickAssembler
  5551.                        allows you to use MEMORY type even though LINK does
  5552.                        not recognize a separate MEMORY type. This feature is
  5553.                        compatible with other linkers that may support a
  5554.                        combine type conforming to the Intel definition of
  5555.                        MEMORY type.
  5556.  
  5557.    AT address          Causes all label and variable addresses defined in the
  5558.                        segment to be relative to address.
  5559.  
  5560.                        The address can be any valid expression but must not
  5561.                        contain a forward reference──that is, a reference to a
  5562.                        symbol defined later in the source file. An AT segment
  5563.                        typically contains no code or initialized data.
  5564.                        Instead, it represents an address template that can be
  5565.                        placed over code or data already in memory, such as a
  5566.                        screen buffer or other absolute memory locations
  5567.                        defined by hardware. The linker will not generate any
  5568.                        code or data for AT segments, but existing code or
  5569.                        data can be accessed by name if it is given a label in
  5570.                        an AT segment. Section 6.6, "Setting the Location
  5571.                        Counter," shows an example of a segment with AT
  5572.                        combine type.
  5573.  
  5574.  
  5575.    If no combine type is given, the segment has private type. Segments having
  5576.    the same name are not combined. Instead, each segment receives its own
  5577.    physical segment when loaded into memory.
  5578.  
  5579.    ──────────────────────────────────────────────────────────────────────────
  5580.    NOTE   Although a given segment name can be used more than once in a
  5581.    source file, each segment definition using that name must have either
  5582.    exactly the same attributes, or attributes that do not conflict. If types
  5583.    are given for an initial segment definition, subsequent definitions for
  5584.    that segment need not specify any types.
  5585.  
  5586.    Normally, you should provide at least one stack segment (having STACK
  5587.    combine type) in a program. If no stack segment is declared, LINK displays
  5588.    a warning message. You can ignore this message if you have a specific
  5589.    reason for not declaring a stack segment. For example, you would not have
  5590.    a separate stack segment in a program in the .COM format.
  5591.    ──────────────────────────────────────────────────────────────────────────
  5592.  
  5593.    Example
  5594.  
  5595.    The following source-code shell illustrates one way in which the combine
  5596.    and align types can be used. Figure 5.1 shows the way LINK would load the
  5597.    sample program into memory.
  5598.  
  5599.                NAME module_1
  5600.  
  5601.    ASEG        SEGMENT BYTE PUBLIC 'CODE'
  5602.    start:      .
  5603.                .
  5604.                .
  5605.    ASEG        ENDS
  5606.  
  5607.    BSEG        SEGMENT WORD COMMON 'DATA'
  5608.                .
  5609.                .
  5610.                .
  5611.    BSEG        ENDS
  5612.  
  5613.    CSEG        SEGMENT PARA STACK 'STACK'
  5614.                .
  5615.                .
  5616.                .
  5617.    CSEG        ENDS
  5618.  
  5619.    DSEG        SEGMENT AT 0B800H
  5620.                .
  5621.                .
  5622.                .
  5623.    DSEG        ENDS
  5624.                END start
  5625.  
  5626.                NAME module_2
  5627.  
  5628.    ASEG        SEGMENT BYTE PUBLIC 'CODE'
  5629.                .
  5630.                .
  5631.                .
  5632.    ASEG        ENDS
  5633.  
  5634.    BSEG        SEGMENT WORD COMMON 'DATA'
  5635.                .
  5636.                .
  5637.                .
  5638.    BSEG        ENDS
  5639.  
  5640.    ┌────────────────────────────────────────────────────────────────────────┐
  5641.    │ This figure can be found in Section 5.2.2.2 of the manual              │
  5642.    └────────────────────────────────────────────────────────────────────────┘
  5643.  
  5644.  
  5645.  5.2.2.3  Controlling Segment Structure with Class Type
  5646.  
  5647.    Class type is a means of associating segments that have different names,
  5648.    but similar purposes. It can be used to control segment order and to
  5649.    identify the code segment.
  5650.  
  5651.    The class name must be enclosed in single quotation marks ('). Class names
  5652.    are not case sensitive unless the /Cl or /Cx option is used during
  5653.    assembly.
  5654.  
  5655.    All segments belong to a class. Segments for which no class name is
  5656.    explicitly stated have the null class name. LINK imposes no restriction on
  5657.    the number or size of segments in a class. The total size of all segments
  5658.    in a class can exceed 64K.
  5659.  
  5660.    ──────────────────────────────────────────────────────────────────────────
  5661.    NOTE   The names assigned for class types of segments should not be used
  5662.    for other symbol definitions in the source file. For example, if you give
  5663.    a segment the class name 'CONSTANT', you should not give the name constant
  5664.    to variables or labels in the source file.
  5665.    ──────────────────────────────────────────────────────────────────────────
  5666.  
  5667.    The linker expects segments having the class name CODE or a class name
  5668.    with the suffix CODE to contain program code. You should always assign
  5669.    this class name to segments containing code.
  5670.  
  5671.    Class type is one of two factors that control the final order of segments
  5672.    in an executable file. The other factor is the order of the segments in
  5673.    the source file (with the /s option or the .SEQ directive) or the
  5674.    alphabetical order of segments (with the /a option or the .ALPHA
  5675.    directive).
  5676.  
  5677.    These factors control different internal behavior, but both affect the
  5678.    final order of segments in the executable file. The sequential or
  5679.    alphabetical order of segments in the source file determines the order in
  5680.    which the assembler writes segments to the object file. The class type can
  5681.    affect the order in which the linker writes segments from object files to
  5682.    the executable file.
  5683.  
  5684.    Segments having the same class type are loaded into memory together,
  5685.    regardless of their sequential or alphabetical order in the source file.
  5686.  
  5687.    ──────────────────────────────────────────────────────────────────────────
  5688.    NOTE   The DOSSEG directive (see Section 5.1.2, "Specifying DOS Segment
  5689.    Order") overrides all other factors in determining segment order.
  5690.    ──────────────────────────────────────────────────────────────────────────
  5691.  
  5692.    Example
  5693.  
  5694.    A_SEG       SEGMENT 'SEG_1'
  5695.    A_SEG       ENDS
  5696.  
  5697.    B_SEG       SEGMENT 'SEG_2'
  5698.    B_SEG       ENDS
  5699.  
  5700.    C_SEG       SEGMENT 'SEG_1'
  5701.    C_SEG       ENDS
  5702.  
  5703.    When QuickAssembler assembles the preceding program fragment, it writes
  5704.    the segments to the object file in sequential or alphabetical order,
  5705.    depending on whether the /a option or the .ALPHA directive was used. In
  5706.    the example above, the sequential and alphabetical order are the same, so
  5707.    the order will be A_SEG, B_SEG, C_SEG in either case.
  5708.  
  5709.    When the linker writes the segments to the executable file, it first
  5710.    checks to see if any segments have the same class type. If they do, it
  5711.    writes them to the executable file together. Thus, A_SEG and C_SEG are
  5712.    placed together because they both have class type 'SEG_1'. The final order
  5713.    in memory is A_SEG, C_SEG, B_SEG.
  5714.  
  5715.    Since LINK processes modules in the order it receives them on the command
  5716.    line, you may not always be able to easily specify the order in which you
  5717.    want segments to be loaded. For example, assume your program has four
  5718.    segments that you want loaded in the following order: _TEXT, _DATA, CONST,
  5719.    and STACK.
  5720.  
  5721.    The _TEXT, CONST, and STACK segments are defined in the first module of
  5722.    your program, but the _DATA segment is defined in the second module. LINK
  5723.    will not put the segments in the proper order because it first loads the
  5724.    segments encountered in the first module.
  5725.  
  5726.    You can avoid this problem by starting your program with dummy segment
  5727.    definitions in the order you wish to load your real segments. The dummy
  5728.    segments can either go at the start of the first module, or they can be
  5729.    placed in a separate include file that is called at the start of the first
  5730.    module. You can then put the actual segment definitions in any order or
  5731.    any module you find convenient.
  5732.  
  5733.    For example, you might call the following include file at the start of the
  5734.    first module of your program:
  5735.  
  5736.    _TEXT       SEGMENT WORD PUBLIC 'CODE'
  5737.    _TEXT       ENDS
  5738.    _DATA       SEGMENT WORD PUBLIC 'DATA'
  5739.    _DATA       ENDS
  5740.    CONST       SEGMENT WORD PUBLIC 'CONST'
  5741.    CONST       ENDS
  5742.    STACK       SEGMENT PARA STACK 'STACK'
  5743.    STACK       ENDS
  5744.  
  5745.    The DOSSEG directive may be more convenient for defining segment order if
  5746.    you are willing to accept the DOS segment-order conventions.
  5747.  
  5748.    Once a segment has been defined, you do not need to specify the align,
  5749.    combine, use, and class types on subsequent definitions. For example, if
  5750.    your code defined dummy segments as shown above, you could define an
  5751.    actual data segment with the following statements:
  5752.  
  5753.    _DATA       SEGMENT
  5754.                .
  5755.                .
  5756.                .
  5757.    _DATA       ENDS
  5758.  
  5759.  
  5760.  5.3  Defining Segment Groups
  5761.  
  5762.    A group is a collection of segments associated with the same starting
  5763.    address. You may wish to use a group if you want several types of data to
  5764.    be organized in separate segments in your source code, but want them all
  5765.    to be accessible from a single, common segment register at run time.
  5766.  
  5767.    Syntax
  5768.  
  5769.    name GROUP segment [[,segment]]...
  5770.  
  5771.    The name is the symbol assigned to the starting address of the group. All
  5772.    labels and variables defined within the segments of the group are relative
  5773.    to the start of the group, rather than to the start of the segments in
  5774.    which they are defined.
  5775.  
  5776.    The segment can be any previously defined segment or a SEG expression (see
  5777.    Section 9.2.4.5).
  5778.  
  5779.    Segments can be added to a group one at a time. For example, you can
  5780.    define and add segments to a group one by one.
  5781.  
  5782.    The GROUP directive does not affect the order in which segments of a group
  5783.    are loaded. Loading order depends on each segment's class, or on the order
  5784.    in which object modules are given to the linker.
  5785.  
  5786.    Segments in a group need not be contiguous. Segments that do not belong to
  5787.    the group can be loaded between segments that do. The only restriction is
  5788.    that the distance (in bytes) between the first byte in the first segment
  5789.    of the group and the last byte in the last segment must not exceed 65,535
  5790.    bytes.
  5791.  
  5792.    ──────────────────────────────────────────────────────────────────────────
  5793.    NOTE   When the .MODEL directive is used, the offset of a group-relative
  5794.    segment refers to the ending address of the segment, not the beginning.
  5795.    For example, the expression OFFSET STACK evaluates to the end of the stack
  5796.    segment.
  5797.    ──────────────────────────────────────────────────────────────────────────
  5798.  
  5799.    Group names can be used with the ASSUME directive (discussed in Section
  5800.    5.4, "Associating Segments with Registers") and as an operand prefix with
  5801.    the segment-override operator (discussed in Section 9.2.3).
  5802.  
  5803.    Example
  5804.  
  5805.    DGROUP      GROUP   ASEG,CSEG
  5806.                ASSUME  ds:DGROUP
  5807.  
  5808.    ASEG        SEGMENT WORD PUBLIC 'DATA'
  5809.                .
  5810.    asym        .
  5811.                .
  5812.    ASEG        ENDS
  5813.  
  5814.    BSEG        SEGMENT WORD PUBLIC 'DATA'
  5815.                .
  5816.    bsym        .
  5817.                .
  5818.    BSEG        ENDS
  5819.  
  5820.    CSEG        SEGMENT WORD PUBLIC 'DATA'
  5821.                .
  5822.    csym        .
  5823.                .
  5824.    CSEG        ENDS
  5825.                END
  5826.  
  5827.    Figure 5.2 shows the order of the example segments in memory. They are
  5828.    loaded in the order in which they appear in the source code (or in
  5829.    alphabetical order if the .ALPHA directive or /s option is specified).
  5830.  
  5831.    ┌────────────────────────────────────────────────────────────────────────┐
  5832.    │ This figure can be found in Section 5.3 of the manual                  │
  5833.    └────────────────────────────────────────────────────────────────────────┘
  5834.  
  5835.    Since ASEG and CSEG are declared part of the same group, they have the
  5836.    same base despite their separation in memory. This means that the symbols
  5837.    asym and csym have offsets from the beginning of the group, which is also
  5838.    the beginning of ASEG. The offset of bsym is from the beginning of BSEG,
  5839.    since it is not part of the group. This sample illustrates the way LINK
  5840.    organizes segments in a group. It is not intended as a typical use of a
  5841.    group.
  5842.  
  5843.  
  5844.  5.4  Associating Segments with Registers
  5845.  
  5846.    Many of the assembler instructions assume a default segment. For example,
  5847.    JMP instructions assume the segment associated with the CS register; PUSH
  5848.    and POP instructions assume the segment associated with the SS register;
  5849.    MOV instructions assume the segment associated with the DS register.
  5850.  
  5851.    When the assembler needs to reference an address, it must know what
  5852.    segment the address is in. It does this by using the default segment or
  5853.    group addresses assigned with the ASSUME directive.
  5854.  
  5855.    ──────────────────────────────────────────────────────────────────────────
  5856.    NOTE   Using the ASSUME directive to tell the assembler which segment to
  5857.    associate with a segment register is not the same as telling the
  5858.    processor. The ASSUME directive only affects assembly-time assumptions.
  5859.    You may need to use instructions to change run-time assumptions.
  5860.    Initializing segment registers at run time is discussed in Section 5.5.
  5861.    ──────────────────────────────────────────────────────────────────────────
  5862.  
  5863.    Syntax
  5864.  
  5865.    ASSUME segmentregister:name [[,segmentregister:name]]...
  5866.    ASSUME segmentregister:NOTHING
  5867.    ASSUME NOTHING
  5868.  
  5869.    The name must be the name of the segment or group that is to be associated
  5870.    with segmentregister. Subsequent instructions that assume a default
  5871.    register for referencing labels or variables automatically assume that if
  5872.    the default segment is segmentregister, the label or variable is in the
  5873.    name segment or group.
  5874.  
  5875.    The ASSUME directive can define a segment for each of the segment
  5876.    registers. The segmentregister can be CS, DS, ES, or SS. The name must be
  5877.    one of the following:
  5878.  
  5879.    ■  The name of a segment defined in the source file with the SEGMENT
  5880.       directive
  5881.  
  5882.    ■  The name of a group defined in the source file with the GROUP directive
  5883.  
  5884.    ■  The keyword NOTHING
  5885.  
  5886.    ■  A SEG expression (see Section 9.2.4.5, "SEG Operator")
  5887.  
  5888.    ■  A string equate that evaluates to a segment or group name (but not a
  5889.       string equate that evaluates to a SEG expression)
  5890.  
  5891.    The keyword NOTHING cancels the current segment selection. For example,
  5892.    the statement ASSUME NOTHING cancels all register selections made by
  5893.    previous ASSUME statements.
  5894.  
  5895.    Usually, a single ASSUME statement defines all four segment registers at
  5896.    the start of the source file. However, you can use the ASSUME directive at
  5897.    any point to change segment assumptions.
  5898.  
  5899.    Using the ASSUME directive to change segment assumptions is often
  5900.    equivalent to changing assumptions with the segment-override operator (:)
  5901.    (see Section 9.2.3). The segment-override operator is more convenient for
  5902.    one-time overrides, whereas the ASSUME directive may be more convenient if
  5903.    previous assumptions must be overridden for a sequence of instructions.
  5904.  
  5905.    Example
  5906.  
  5907.                DOSSEG
  5908.                .MODEL  large       ; DS automatically assumed to @data
  5909.                .STACK  100h
  5910.                .DATA
  5911.    d1          DW      7
  5912.                .FARDATA
  5913.    d2          DW      9
  5914.  
  5915.                .CODE
  5916.    start:      mov     ax,@data    ; Initialize near data
  5917.                mov     ds,ax
  5918.                mov     ax,@fardata ; Initialize far data
  5919.                mov     es,ax
  5920.                .
  5921.                .
  5922.                .
  5923.  
  5924.    ; Method 1 for series of instructions that need override
  5925.    ; Use segment override for each statement
  5926.  
  5927.                mov     ax,es:d2
  5928.                .
  5929.                .
  5930.                .
  5931.                mov     es:d2,bx
  5932.  
  5933.    ; Method 2 for series of instructions that need override
  5934.    ; Use ASSUME at beginning of series of instructions
  5935.  
  5936.                ASSUME  es:@fardata
  5937.                mov     cx,d2
  5938.                .
  5939.                .
  5940.                .
  5941.                mov     d2,dx
  5942.  
  5943.  
  5944.  5.5  Initializing Segment Registers
  5945.  
  5946.    Assembly-language programs must initialize segment values for each segment
  5947.    register before instructions that reference the segment register can be
  5948.    used in the source program.
  5949.  
  5950.    Initializing segment registers is different from assigning default values
  5951.    for segment registers with the ASSUME statement. The ASSUME directive
  5952.    tells the assembler what segments to use at assembly time. Initializing
  5953.    segments gives them an initial value that will be used at run time.
  5954.  
  5955.    The .STARTUP directive generates all the initialization code described in
  5956.    this section. This directive must be preceded by the .MODEL directive. If
  5957.    the .MODEL directive was followed by the farStack attribute, .STARTUP does
  5958.    not adjust SS and SP. Otherwise, it assumes the nearStack default, which
  5959.    sets SS equal to DS as described in Section 5.5.3, "Initializing the SS
  5960.    and SP Registers." When you use this default, the combined stack and near
  5961.    data must not exceed 64K.
  5962.  
  5963.    If you use .STARTUP, you don't need to enter any of the code in this
  5964.    section, except for the END statement. (However, if you use .STARTUP, you
  5965.    don't need to specify a starting address.) Make sure that you place the
  5966.    .STARTUP directive at the point you want your program to start executing,
  5967.    because the assembler automatically initializes CS:IP to point to the
  5968.    beginning of the code generated by .STARTUP.
  5969.  
  5970.  
  5971.  5.5.1  Initializing the CS and IP Registers
  5972.  
  5973.    The CS and IP registers are initialized by specifying a starting address
  5974.    with the END directive.
  5975.  
  5976.    Syntax
  5977.  
  5978.    END [[startaddress]]
  5979.  
  5980.    The startaddress is a label or expression identifying the address where
  5981.    you want execution to begin when the program is loaded. Normally, a label
  5982.    for the start address should be placed at the address of the first
  5983.    instruction in the code segment.
  5984.  
  5985.    The CS segment is initialized to the value of startaddress. The IP
  5986.    register is normally initialized to 0. You can change the initial value of
  5987.    the IP register by using the ORG directive (see Section 6.6, "Setting the
  5988.    Location Counter") just before the startaddress label. For example,
  5989.    programs in the .COM format use ORG 100h to initialize the IP register to
  5990.    256 (100 hexadecimal).
  5991.  
  5992.    If a program consists of a single source module, the start address is
  5993.    required for that module. If a program has several modules, all modules
  5994.    must terminate with an END directive, but only one of them can define a
  5995.    start address.
  5996.  
  5997.    ──────────────────────────────────────────────────────────────────────────
  5998.    WARNING   One, and only one, module must define a start address. If you do
  5999.    not specify a start address, none is assumed. Neither QuickAssembler nor
  6000.    LINK will generate an error message, but your program will probably start
  6001.    execution at the wrong address.
  6002.    ──────────────────────────────────────────────────────────────────────────
  6003.  
  6004.    Example
  6005.  
  6006.    ; Module 1
  6007.                .CODE
  6008.    start:      .                  ; First executable instruction
  6009.                .
  6010.                .
  6011.                EXTRN   task:NEAR
  6012.                call    task
  6013.                .
  6014.                .
  6015.                .
  6016.                END     start      ; Starting address defined in main module
  6017.  
  6018.    ; Module 2
  6019.                PUBLIC  task
  6020.                .CODE
  6021.    task        PROC
  6022.                .
  6023.                .
  6024.                .
  6025.    task        ENDP
  6026.                END                ; No starting address in secondary module
  6027.  
  6028.    If Module 1 and Module 2 are linked into a single program, it is essential
  6029.    that only the calling module define a starting address.
  6030.  
  6031.  
  6032.  5.5.2  Initializing the DS Register
  6033.  
  6034.    The DS register must be initialized to the address of the segment that
  6035.    will be used for data.
  6036.  
  6037.    The address of the segment or group for the initial data segment must be
  6038.    loaded into the DS register. This is done in two statements because a
  6039.    memory value cannot be loaded directly into a segment register. The
  6040.    segment-setup lines typically appear at the start or very near the start
  6041.    of the code segment.
  6042.  
  6043.    Example 1
  6044.  
  6045.    _DATA       SEGMENT WORD PUBLIC 'DATA'
  6046.                .
  6047.                .
  6048.                .
  6049.    _DATA       ENDS
  6050.    _TEXT       SEGMENT BYTE PUBLIC 'CODE'
  6051.                ASSUME  cs:_TEXT,ds:_DATA
  6052.    start:      mov     ax,_DATA           ; Load start of data segment
  6053.                mov     ds,ax              ; Transfer to DS register
  6054.                .
  6055.                .
  6056.                .
  6057.    _TEXT       ENDS
  6058.                END     start
  6059.  
  6060.    If you are using the Microsoft naming convention and segment order, the
  6061.    address loaded into the DS register is not a segment address but the
  6062.    address of DGROUP, as shown in Example 2. With simplified segment
  6063.    directives, the address of DGROUP is represented by the predefined equate
  6064.    @data.
  6065.  
  6066.    Example 2
  6067.  
  6068.                DOSSEG
  6069.                .MODEL  SMALL
  6070.                .DATA
  6071.                .
  6072.                .
  6073.                .
  6074.                .CODE
  6075.    start:      mov     ax,@data          ; Load start of DGROUP (@data)
  6076.                mov     ds,ax             ; Transfer to DS register
  6077.                .
  6078.                .
  6079.                .
  6080.                END     start
  6081.  
  6082.  
  6083.  5.5.3  Initializing the SS and SP Registers
  6084.  
  6085.    At load time, DOS sets SS to the segment address of the last segment
  6086.    having combine type STACK, and SP to the size of the stack. (The linker
  6087.    actually determines the value of SS:SP and places this value in the
  6088.    executable-file header. DOS sets SS and SP as indicated in the file
  6089.    header.)
  6090.  
  6091.    If you use a stack segment with combine type STACK or use the .STACK
  6092.    directive, the program automatically loads with SS and SP initialized, as
  6093.    described above.
  6094.  
  6095.    However, this basic initialization does not set SS equal to DS. If the
  6096.    program contains the statement ASSUME SS:DGROUP, it will be prone to
  6097.    errors. The following code resets SS and SP so that SS has the same value
  6098.    as DS. The code then adjusts SP upward so that SS:SP points to the
  6099.    same physical address it did before. Since hardware interrupts use
  6100.    the same stack as the program, you should turn off interrupts while
  6101.    changing the stack. Most 8086-family processors turn off interrupts
  6102.    automatically when you adjust SS or SP, but early versions of the 8088 do n
  6103.  
  6104.    Example 1
  6105.  
  6106.                .MODEL  small
  6107.                .STACK  100h               ; Initialize "STACK"
  6108.                .DATA
  6109.                .
  6110.                .
  6111.                .
  6112.                .CODE
  6113.    start:      mov     ax,@data           ; Load segment location
  6114.                mov     ds,ax              ;   into DS register
  6115.                cli                        ; Turn off interrupts
  6116.                mov     ss,ax              ; Load same value as DS into SS
  6117.                mov     sp,OFFSET STACK    ; Give SP new stack size
  6118.                sti                        ; Turn interrupts back on
  6119.                .
  6120.                .
  6121.                .
  6122.  
  6123.    This example reinitializes SS so that it has the same value as DS, and it
  6124.    adjusts SP to reflect the new stack offset. Microsoft high-level-language
  6125.    compilers do this so that stack variables in near procedures can be
  6126.    accessed relative to either SS or DS.
  6127.  
  6128.    However, this code only works correctly if you use .MODEL and you declare
  6129.    a stack segment in just one module. The following code handles the more
  6130.    general case. The .STARTUP directive generates this code:
  6131.  
  6132.    Example 2
  6133.  
  6134.    start_label:
  6135.                mov     dx,DGROUP    ; Move DGROUP into DS and DX
  6136.                mov     ds,dx
  6137.                mov     bx,ss        ; BX = STACK - DGROUP
  6138.                sub     bx,dx        ;
  6139.                shl     bx,1         ; Multiply difference by 16
  6140.                shl     bx,1         ;   and leave result in BX
  6141.                shl     bx,1
  6142.                shl     bx,1
  6143.                cli
  6144.                mov     ss,dx        ; Move DGROUP into SS
  6145.                add     sp,bx        ; Adjust SP upward by
  6146.                sti                  ;   (STACK - DGROUP) * 16
  6147.  
  6148.    The code above sets SS and SP so that SS equals DS. This code works
  6149.    correctly no matter how many modules declare a stack segment.
  6150.  
  6151.  
  6152.  5.5.4  Initializing the ES Register
  6153.  
  6154.    The ES register is not automatically initialized. If your program uses the
  6155.    ES register, you must initialize it by moving the appropriate segment
  6156.    value into the register.
  6157.  
  6158.    Example
  6159.  
  6160.                ASSUME  es:@fardata        ; Tell the assembler
  6161.                mov     ax,@fardata        ; Tell the processor
  6162.                mov     es,ax
  6163.  
  6164.  
  6165.  5.6  Nesting Segments
  6166.  
  6167.    Segments can be nested. When QuickAssembler encounters a nested segment,
  6168.    it temporarily suspends assembly of the enclosing segment and begins
  6169.    assembly of the nested segment. When the nested segment has been
  6170.    assembled, Quick-Assembler continues assembly of the enclosing segment.
  6171.  
  6172.    Nesting of segments makes it possible to mix segment definitions in
  6173.    programs that use simplified segment directives for most segment
  6174.    definitions. When a full segment definition is given, the new segment is
  6175.    nested in the simplified segment in which it is defined.
  6176.  
  6177.    Example 1
  6178.  
  6179.    ; Macro to print message on the screen
  6180.    ; Uses full segment definitions - segments nested
  6181.  
  6182.    message     MACRO   text
  6183.                LOCAL   symbol
  6184.    _DATA       SEGMENT WORD PUBLIC 'DATA'
  6185.    symbol      DB      &text
  6186.                DB      13,10,"$"
  6187.    _DATA       ENDS
  6188.                mov     ah,09h
  6189.                mov     dx,OFFSET symbol
  6190.                int     21h
  6191.                ENDM
  6192.  
  6193.    _TEXT       SEGMENT BYTE PUBLIC 'CODE'
  6194.                .
  6195.                .
  6196.                .
  6197.                message "Please insert disk"
  6198.  
  6199.    In the example above, a macro called from inside of the code segment
  6200.    (_TEXT) allocates a variable within a nested data segment (_DATA). This
  6201.    has the effect of allocating more data space on the end of the data
  6202.    segment each time the macro is called. The macro can be used for messages
  6203.    appearing only once in the source code.
  6204.  
  6205.    Example 2
  6206.  
  6207.    ; Macro to print message on the screen
  6208.    ; Uses simplified segment directives - segments not nested
  6209.  
  6210.    message     MACRO   text
  6211.                LOCAL   symbol
  6212.                .DATA
  6213.    symbol      DB      &text
  6214.                DB      13,10,"$"
  6215.                .CODE
  6216.                mov     ah,09h
  6217.                mov     dx,OFFSET symbol
  6218.                int     21h
  6219.                ENDM
  6220.  
  6221.                .CODE
  6222.                .
  6223.                .
  6224.                .
  6225.                message "Please insert disk"
  6226.  
  6227.    Although Example 2 has the same practical effect as Example 1,
  6228.    Quick-Assembler handles the two macros differently. In Example 1, assembly
  6229.    of the outer (code) segment is suspended rather than terminated. In
  6230.    Example 2, assembly of the code segment terminates, assembly of the data
  6231.    segment starts and terminates, and then assembly of the code segment is
  6232.    restarted.
  6233.  
  6234.  
  6235.  
  6236.  ────────────────────────────────────────────────────────────────────────────
  6237.  Chapter 6:  Defining Constants, Labels, and Variables
  6238.  
  6239.  
  6240.    This chapter explains how to define constants, labels, variables, and
  6241.    other symbols that refer to instruction and data locations within
  6242.    segments.
  6243.  
  6244.    Constants are important in QuickAssembler, just as they are in other
  6245.    languages. You can use constants as immediate operands in instructions and
  6246.    as initial values in data declarations. QuickAssembler supports a number
  6247.    of useful radixes (including binary and hexadecimal), as described in
  6248.    Section 6.1.
  6249.  
  6250.    QuickAssembler lets you use symbols as well as constants. Sections 6.2,
  6251.    "Assigning Names to Symbols," and 6.3, "Using Type Specifiers," present
  6252.    the basic principles of generating symbolic names.
  6253.  
  6254.    Most symbols are either code labels or variable names. Section 6.4,
  6255.    "Defining Code Labels," and Section 6.5, "Defining and Initializing
  6256.    Data," describe how to define these symbols.
  6257.  
  6258.    This chapter tells you how to assign labels and most kinds of variables.
  6259.    (Multifield variables, such as structures and records, are discussed in
  6260.    Chapter 7, "Using Structures and Records.") Chapter 6 also discusses
  6261.    related directives, including those that control the location counter
  6262.    directly. The assembler uses the location counter to assign addresses to
  6263.    symbols.
  6264.  
  6265.  
  6266.  6.1  Constants
  6267.  
  6268.    Constants can be used in source files to specify numbers or strings that
  6269.    are set or initialized at assembly time. The assembler recognizes four
  6270.    types of constant values:
  6271.  
  6272.    1. Integers
  6273.  
  6274.    2. Packed binary coded decimals
  6275.  
  6276.    3. Real numbers
  6277.  
  6278.    4. Strings
  6279.  
  6280.  
  6281.  6.1.1  Integer Constants
  6282.  
  6283.    Integer constants represent integer values. They can be used in a variety
  6284.    of contexts in assembly-language source code. For example, they can be
  6285.    used in data declarations and equates, or as immediate operands.
  6286.  
  6287.    Packed decimal integers are a special kind of integer constant that can
  6288.    only be used to initialize binary coded decimal (BCD) variables. They are
  6289.    described in Sections 6.1.2, "Packed Binary Coded Decimal Constants," and
  6290.    6.5.1.2, "Binary Coded Decimal Variables."
  6291.  
  6292.    Integer constants can be specified in binary, octal, decimal, or
  6293.    hexadecimal values. Table 6.1 shows the legal digits for each of these
  6294.    radixes. For hexadecimal radix, the digits can be either uppercase or
  6295.    lowercase letters.
  6296.  
  6297.    Table 6.1 Digits Used with Each Radix
  6298.  
  6299.    Radix           Base            Digits
  6300.    ──────────────────────────────────────────────────────────────────────────
  6301.    Binary          2               0 1
  6302.  
  6303.    Octal           8               0 1 2 3 4 5 6 7
  6304.  
  6305.    Decimal         10              0 1 2 3 4 5 6 7 8 9
  6306.  
  6307.    Hexadecimal     16              0 1 2 3 4 5 6 7 8 9 A B C D E F
  6308.  
  6309.    ──────────────────────────────────────────────────────────────────────────
  6310.  
  6311.  
  6312.    The radix for an integer can be defined for a specific integer by using
  6313.    radix specifiers, or a default radix can be defined globally with the
  6314.    .RADIX directive.
  6315.  
  6316.  
  6317.  6.1.1.1  Specifying Integers with Radix Specifiers
  6318.  
  6319.    The radix for an integer constant can be given by putting one of the
  6320.    following radix specifiers after the last digit of the number:
  6321.  
  6322.    Radix               Specifier
  6323.    ──────────────────────────────────────────────────────────────────────────
  6324.    Binary              B
  6325.  
  6326.    Octal               Q or O
  6327.  
  6328.    Decimal             D
  6329.  
  6330.    Hexadecimal         H
  6331.  
  6332.  
  6333.    Radix specifiers can be given in either uppercase or lowercase letters;
  6334.    sample code in this manual uses lowercase letters.
  6335.  
  6336.    Hexadecimal numbers must always start with a decimal digit (0-9). If
  6337.    necessary, put a leading 0 at the left of the number to distinguish
  6338.    between symbols and hexadecimal numbers that start with a letter. For
  6339.    example, 0ABCh is interpreted as a hexadecimal number, but ABCh is
  6340.    interpreted as a symbol. The hexadecimal digits A through F can be either
  6341.    uppercase or lowercase letters. Sample code in this manual uses uppercase
  6342.    letters.
  6343.  
  6344.    If no radix is given, the assembler interprets the integer by using the
  6345.    current default radix. The initial default radix is decimal, but you can
  6346.    change the default with the .RADIX directive.
  6347.  
  6348.    Examples
  6349.  
  6350.    n360        EQU    01011010b + 132q + 5Ah + 90d  ; 4 * 90
  6351.    n60         EQU    00001111b +  17o + 0Fh + 15d  ; 4 * 15
  6352.  
  6353.  
  6354.  6.1.1.2  Setting the Default Radix
  6355.  
  6356.    The .RADIX directive sets the default radix for integer constants in the
  6357.    source file.
  6358.  
  6359.    Syntax
  6360.  
  6361.    .RADIX expression
  6362.  
  6363.    The expression must evaluate to a number in the range 2-16. It defines
  6364.    whether the numbers are binary, octal, decimal, hexadecimal, or numbers of
  6365.    some other base.
  6366.  
  6367.    Numbers given in expression are always considered decimal, regardless of
  6368.    the current default radix. The initial default radix is decimal.
  6369.  
  6370.    Note that the .RADIX directive does not affect real numbers initialized as
  6371.    variables with the DD, DQ, or DT directive. Initial values for real-number
  6372.    variables declared with these directives are always evaluated as decimal
  6373.    unless a radix specifier is appended.
  6374.  
  6375.    Also, the .RADIX directive does not affect the optional radix specifiers,
  6376.    B and D, used with integer numbers. When the letters B or D appear at the
  6377.    end of any integer, they are always considered to be a radix specifier
  6378.    even if the current radix is 16.
  6379.  
  6380.    For example, if the input radix is 16, the number 0ABCD will be
  6381.    interpreted as 0ABC decimal, an illegal number, instead of as 0ABCD
  6382.    hexadecimal, as intended. Type 0ABCDh to specify 0ABCD in hexadecimal.
  6383.    Similarly, the number 11B will be treated as 11 binary, a legal number,
  6384.    but not as 11B hexadecimal as intended. Type 11Bh to specify 11B in
  6385.    hexadecimal.
  6386.  
  6387.    Examples
  6388.  
  6389.                .RADIX  16         ; Set default radix to hexadecimal
  6390.                .RADIX  2          ; Set default radix to binary
  6391.  
  6392.  
  6393.  6.1.2  Packed Binary Coded Decimal Constants
  6394.  
  6395.    When an integer constant is used with the DT directive, the number is
  6396.    interpreted by default as a packed binary coded decimal (BCD) number. You
  6397.    can use the D radix specifier to override the default and initialize
  6398.    10-byte integers as binary-format integers.
  6399.  
  6400.    The syntax for specifying binary coded decimals is exactly the same as for
  6401.    other integers. However, the assembler encodes binary coded decimals in a
  6402.    completely different way. See Section 6.5.1.2, "Binary Coded Decimal
  6403.    Variables," for complete information on storage of binary coded decimals.
  6404.  
  6405.    Examples
  6406.  
  6407.    positive    DT     1234567890  ; Encoded as 00000000001234567890h
  6408.    negative    DT     -1234567890 ; Encoded as 80000000001234567890h
  6409.  
  6410.  
  6411.  6.1.3  Real-Number Constants
  6412.  
  6413.    A real number is a number consisting of an integer part, a fractional
  6414.    part, and an exponent. Real numbers are usually represented in decimal
  6415.    format.
  6416.  
  6417.    Syntax
  6418.  
  6419.    [[+ | -]] integer.fraction[[E[[+ | -]]exponent]]
  6420.  
  6421.    The integer and fraction parts combine to form the value of the number.
  6422.    This value is stored internally as a unit and is called the mantissa. It
  6423.    may be signed. The optional exponent follows the exponent indicator (E).
  6424.    It represents the magnitude of the value and is stored internally as a
  6425.    unit. If no exponent is given, 1 is assumed. If an exponent is given, it
  6426.    may be signed.
  6427.  
  6428.    During assembly, the assembler converts real-number constants given in
  6429.    decimal format to a binary format. The sign, exponent, and mantissa of the
  6430.    real number are encoded as bit fields within the number. See Section
  6431.    6.5.1.4, "Real-Number Variables," for an explanation of how real numbers
  6432.    are encoded.
  6433.  
  6434.    You can specify the encoded format directly using hexadecimal digits (0-9
  6435.    or A-F). The number must begin with a decimal digit (0-9) and cannot be
  6436.    signed. It must be followed by the real-number designator (R). This
  6437.    designator is used the same as a radix designator except it specifies that
  6438.    the given hexadecimal number should be interpreted as a real number.
  6439.  
  6440.    Real numbers can only be used to initialize variables with the DD, DQ, and
  6441.    DT directives. They cannot be used in expressions. The maximum number of
  6442.    digits in the number and the maximum range of exponent values depend on
  6443.    the directive. The number of digits for encoded numbers used with DD, DQ,
  6444.    and DT must be 8, 16, and 20 digits, respectively. (If a leading 0 is
  6445.    supplied, the number must be 9, 17, or 21 digits.) See Section 6.5.1.4,
  6446.    "Real-Number Variables," for an explanation of how real numbers are
  6447.    encoded.
  6448.  
  6449.    ──────────────────────────────────────────────────────────────────────────
  6450.    NOTE  Real numbers will be encoded differently depending upon whether you
  6451.    use the .MSFLOAT directive. By default, real numbers are encoded in the
  6452.    IEEE format. The .MSFLOAT directive overrides the default and specifies
  6453.    Microsoft Binary format. See Section 6.5.1.4, "Real-Number Variables,"
  6454.    for a description of these formats.
  6455.    ──────────────────────────────────────────────────────────────────────────
  6456.  
  6457.    Example
  6458.  
  6459.    ; Real numbers
  6460.    shrt        DD     25.23
  6461.    long        DQ     2.523E1
  6462.    ten_byte    DT     2523.0E-2
  6463.  
  6464.    ; Assumes .MSFLOAT
  6465.    mbshort     DD     81000000r             ; 1.0 as Microsoft Binary short
  6466.    mblong      DQ     8100000000000000r     ; 1.0 as Microsoft Binary long
  6467.  
  6468.    ; Assumes default IEEE format
  6469.    ieeeshort   DD     3F800000r             ; 1.0 as IEEE short
  6470.    ieeelong    DQ     3FF0000000000000r     ; 1.0 as IEEE long
  6471.  
  6472.    ; The same regardless of processor directives
  6473.    temporary   DT     3FFF8000000000000000r ; 1.0 as 10-byte temporary real
  6474.  
  6475.  
  6476.  6.1.4  String Constants
  6477.  
  6478.    A string constant consists of one or more ASCII characters enclosed in
  6479.    single or double quotation marks. Strings are interpreted as lists of
  6480.    characters having the ASCII values of the characters in the string.
  6481.  
  6482.    Syntax
  6483.  
  6484.    'characters'
  6485.    "characters"
  6486.  
  6487.    String constants are case sensitive. A string constant consisting of a
  6488.    single character is sometimes called a character constant.
  6489.  
  6490.    Single quotation marks must be encoded twice when used literally within
  6491.    string constants that are also enclosed by single quotation marks.
  6492.    Similarly, double quotation marks must be encoded twice when used in
  6493.    string constants that are also enclosed by double quotation marks.
  6494.  
  6495.    Examples
  6496.  
  6497.    char        DB      'a'
  6498.    char2       DB      "a"
  6499.    message     DB      "This is a message."
  6500.    warn        DB      'Can"t find file.'          ; Can't find file.
  6501.    warn2       DB      "Can't find file."          ; Can't find file.
  6502.    string      DB      "This ""value"" not found." ; This "value" not found.
  6503.    string2     DB      'This "value" not found.'   ; This "value" not found.
  6504.  
  6505.  
  6506.  6.1.5  Determining Floating-Point Format
  6507.  
  6508.    The .MSFLOAT directive disables all coprocessor instructions and specifies
  6509.    that initialized real-number variables be encoded in the Microsoft Binary
  6510.    format. Without this directive, initialized real-number variables are
  6511.    encoded in the IEEE format. This is a change from Versions 4.0 and earlier
  6512.    of the Microsoft Macro Assembler, which used Microsoft Binary format by
  6513.    default and required a coprocessor directive or the /R option to specify
  6514.    IEEE format. .MSFLOAT must be used for programs that require real-number
  6515.    data in the Microsoft Binary format. Section 6.5.1.4, "Real-Number
  6516.    Variables," describes real-number data formats and the factors to consider
  6517.    in choosing a format.
  6518.  
  6519.  
  6520.  6.2  Assigning Names to Symbols
  6521.  
  6522.    A symbol is a name that represents a value. Symbols are one of the most
  6523.    important elements of assembly-language programs. Elements that must be
  6524.    represented symbolically in assembly-language source code include
  6525.    variables, address labels, macros, segments, procedures, records, and
  6526.    structures. Constants, expressions, and strings can also be represented
  6527.    symbolically.
  6528.  
  6529.    Symbol names are combinations of letters (both uppercase and lowercase),
  6530.    digits, and special characters. The QuickAssembler recognizes the
  6531.    following character set:
  6532.  
  6533.    A-Z a-z 0-9
  6534.  
  6535.    ? @ _ $ : . [ ] ( ) < > { } + - / *
  6536.  
  6537.    & % ! ' ~ | \ = # ^ ; , ` "
  6538.  
  6539.    Letters, digits, and some characters can be used in symbol names, but some
  6540.    restrictions on how certain characters can be used or combined are listed
  6541.    below:
  6542.  
  6543.    ■  A name can have any combination of uppercase and lowercase letters.
  6544.       Within the QC integrated environment, the default behavior (Preserve
  6545.       Extrn) is for the assembler to convert all symbol names to uppercase
  6546.       unless they are public or external. When you use simplified segment
  6547.       directives, all procedure labels declared with PROC are automatically
  6548.       public.
  6549.  
  6550.       When you use QCL, all lowercase letters are converted to uppercase by
  6551.       the assembler, unless you give the /Cl assembly option, or you declare
  6552.       the name with a PROC, PUBLIC, or EXTRN directive and you give the /Cx
  6553.       option. The /Cl and /Cx options correspond to the assembler flags
  6554.       Preserve Case and Preserve Extrn, respectively, within the QC
  6555.       environment.
  6556.  
  6557.    ■  Digits may be used within a name, but not as the first character.
  6558.  
  6559.    ■  A name can be given any number of characters, but only the first 31 are
  6560.       used. All other characters are ignored.
  6561.  
  6562.    ■  The following characters may be used at the beginning of a name or
  6563.       within a name: underscore (_), question mark (?), dollar sign ($), and
  6564.       at sign (@).
  6565.  
  6566.    ■  The period (.) is an operator and cannot be used within a name, but it
  6567.       can be used as the first character of a name.
  6568.  
  6569.    ■  A name may not be the same as any reserved name. Note that two special
  6570.       characters, the question mark (?) and the dollar sign ($), are reserved
  6571.       names and therefore can't stand alone as symbol names.
  6572.  
  6573.    A reserved name is any name with a special, predefined meaning to the
  6574.    assembler. Reserved names include instruction and directive mnemonics,
  6575.    register names, and operator names. All uppercase and lowercase letter
  6576.    combinations of these names are treated as the same name.
  6577.  
  6578.    The following is a list of names that are always reserved by the
  6579.    assembler. Using any of these names for a symbol results in an error.
  6580.  
  6581.    $                 DWORD               GE                  %OUT
  6582.    *                 ELSE                GROUP               PAGE
  6583.    +                 ELSEIF              GT                  PROC
  6584.    -                 ELSEIF1             HIGH                PTR
  6585.    .                 ELSEIF2             IF                  PUBLIC
  6586.    /                 ELSEIFB             IF1                 PURGE
  6587.    =                 ELSEIFDEF           IF2                 QWORD
  6588.    ?                 ELSEIFDIF           IFB                 .RADIX
  6589.    []                ELSEIFDIFI          IFDEF               RECORD
  6590.    .186              ELSEIFE             IFDIF               REPT
  6591.    .286              ELSEIFIDN           IFE                 .SALL
  6592.    .286P             ELSEIFIDNI          IFIDN               SEG
  6593.    .287              ELSEIFNB            IFNB                SEGMENT
  6594.    .386              ELSEIFNDEF          IFNDEF              .SEQ
  6595.    .386P             END                 INCLUDE             .SFCOND
  6596.    .387              ENDIF               INCLUDELIB          SHL
  6597.    .8086             ENDM                IRP                 SHORT
  6598.    .8087             ENDP                IRPC                SHR
  6599.    ALIGN             ENDS                LABEL               SIZE
  6600.    .ALPHA            EQ                  .LALL               SIZESTR
  6601.    AND               EQU                 LE                  .STACK
  6602.    ASSUME            .ERR                LENGTH              .STARTUP
  6603.    BYTE              .ERR1               .LFCOND             STRUC
  6604.    CATSTR            .ERR2               .LIST               SUBSTR
  6605.    .CODE             .ERRB               LOCAL               SUBTTL
  6606.    COMM              .ERRDEF             LOW                 TBYTE
  6607.    COMMENT           .ERRDIF             LT                  .TFCOND
  6608.    .CONST            .ERRE               MACRO               THIS
  6609.    .CREF             .ERRIDN             MASK                TITLE
  6610.    .DATA             .ERRNB              MOD                 TYPE
  6611.    .DATA?            .ERRNDEF            .MODEL              .TYPE
  6612.    DB                .ERRNZ              NAME                WIDTH
  6613.    DD                EVEN                NE                  WORD
  6614.    DOSSEG            EXITM               NEAR                .XALL
  6615.    DQ                EXTRN               NOT                 .XCREF
  6616.    DS                FAR                 OFFSET              .XLIST
  6617.    DT                .FARDATA            OR                  XOR
  6618.  
  6619.    In addition to the names listed above, instruction mnemonics and register
  6620.    names are considered reserved names. Instructions can vary depending on
  6621.    the processor directives given in the source file. For example, ENTER is
  6622.    recognized as a reserved word if you have enabled 286 instructions with
  6623.    the .286 directive. Section 18.3 describes processor directives.
  6624.    Instruction mnemonics for each processor are listed in the on-line Help
  6625.    system. Register names are listed in Section 2.6.2, "Register Operands."
  6626.  
  6627.  
  6628.  6.3  Using Type Specifiers
  6629.  
  6630.    Some statements require type specifiers to give the size or type of an
  6631.    operand. There are two kinds of type specifiers: those that specify the
  6632.    size of a variable or other memory operand, and those that specify the
  6633.    distance of a label.
  6634.  
  6635.    The type specifiers that give the size of a memory operand are listed
  6636.    below with the number of bytes specified by each:
  6637.  
  6638.    Specifier           Number of Bytes
  6639.    ──────────────────────────────────────────────────────────────────────────
  6640.    BYTE                1
  6641.  
  6642.    WORD                2
  6643.  
  6644.    DWORD               4
  6645.  
  6646.    QWORD               8
  6647.  
  6648.    TBYTE               10
  6649.  
  6650.  
  6651.    In some contexts, ABS can also be used as a type specifier that indicates
  6652.    an operand is a constant rather than a memory operand.
  6653.  
  6654.    The type specifiers that give the distance of a label are listed below:
  6655.  
  6656.    Specifier           Description
  6657.    ──────────────────────────────────────────────────────────────────────────
  6658.    FAR                 The label references both the segment and offset of
  6659.                        the label.
  6660.  
  6661.    NEAR                The label references only the offset of the label.
  6662.  
  6663.    PROC                The label has the default type (NEAR or FAR) of the
  6664.                        current memory model. The default size is always NEAR
  6665.                        if you use full segment definitions. If you use
  6666.                        simplified segment directives (see Section 5.1), the
  6667.                        default type is NEAR for small and compact models or
  6668.                        FAR for medium, large, and huge models.
  6669.  
  6670.  
  6671.    Directives that use type specifiers include LABEL, PROC, EXTRN, and COMM.
  6672.    Operators that use type specifiers include PTR and THIS.
  6673.  
  6674.  
  6675.  6.4  Defining Code Labels
  6676.  
  6677.    Code labels give symbolic names to the addresses of instructions in the
  6678.    code segment. These labels can be used as the operands to jump, call, and
  6679.    loop instructions to transfer program control to a new instruction.
  6680.  
  6681.  
  6682.  6.4.1  Near-Code Labels
  6683.  
  6684.    Near-label definitions create instruction labels that have NEAR type.
  6685.    These instruction labels can be used to access the address of the label
  6686.    from other statements.
  6687.  
  6688.    Syntax
  6689.  
  6690.    name:
  6691.  
  6692.    The name must be followed by a colon (:). The segment containing the
  6693.    definition must be the one that the assembler currently associates with
  6694.    the CS register. The ASSUME directive is used to associate a segment with
  6695.    a segment register (see Section 5.4, "Associating Segments with
  6696.    Registers"). A near label can appear on a line by itself or on a line with
  6697.    an instruction.
  6698.  
  6699.    Near-code labels have different behavior depending on whether they are
  6700.    used in a procedure with the extended PROC syntax. When the extended PROC
  6701.    feature is used (which requires that .MODEL and a language must be
  6702.    specified), near labels are local to the procedure. This functionality is
  6703.    explained in Section 15.3.7, "Variable Scope."
  6704.  
  6705.    If the full segments are used or if the language argument is not supplied
  6706.    to the .MODEL directive, near labels are known throughout the module in
  6707.    which they occur. The same label name can be used in different modules as
  6708.    long as each label is only referenced by instructions in its own module.
  6709.    If a label must be referenced by instructions in another module, it must
  6710.    be given a unique name and declared with the PUBLIC and EXTRN directives,
  6711.    as described in Chapter 8, "Creating Programs from Multiple Modules."
  6712.  
  6713.    Examples
  6714.  
  6715.                cmp    ax,5        ; Compare with 5
  6716.                ja     bigger
  6717.                jb     smaller
  6718.                .                  ; Instructions if AX = 5
  6719.                .
  6720.                .
  6721.                jmp    done
  6722.    bigger:     .                  ; Instructions if AX > 5
  6723.                .
  6724.                .
  6725.                jmp    done
  6726.    smaller:    .                  ; Instructions if AX < 5
  6727.                .
  6728.                .
  6729.    done:
  6730.  
  6731.  
  6732.  6.4.2  Anonymous Labels
  6733.  
  6734.    The assembler provides a way to generate automatic labels for jump
  6735.    instructions. To define a label, use two at signs (@@) followed by a colon
  6736.    (:). To jump to the nearest preceding anonymous label, use @B (back) in
  6737.    the jump instruction's operand field; to jump to the nearest following
  6738.    anonymous label, use @F (forward) in the operand field.
  6739.  
  6740.    You can use two at signs (@@) to define any number of anonymous labels in
  6741.    your program. The items @B and @F always refer to the nearest occurrences
  6742.    of @@, so there is never any conflict between different anonymous labels.
  6743.  
  6744.    Anonymous labels are best used for conditionally executing a few lines of
  6745.    code. The advantage is that you do not need to continually think up new
  6746.    label names. The disadvantage is that they do not provide a meaningful
  6747.    name. You should mark major divisions of a program with actual named
  6748.    labels.
  6749.  
  6750.    The following example shows a typical sequence of code with a
  6751.    jump-to-label instruction:
  6752.  
  6753.    ; DX is 20, unless CX is less than -20, then make DX 30
  6754.                mov    dx,20
  6755.                cmp    cx,-20
  6756.                jge    greatequ
  6757.                mov    dx,30
  6758.    greatequ:
  6759.  
  6760.    Here are the same lines rewritten to use an anonymous label:
  6761.  
  6762.    ; DX is 20, unless CX is less than -20, then make DX 30
  6763.                mov    dx,20
  6764.                cmp    cx,-20
  6765.                jge    @F
  6766.                mov    dx,30
  6767.    @@:
  6768.  
  6769.  
  6770.  6.4.3  Procedure Labels
  6771.  
  6772.    The easiest way to declare a procedure is to use the PROC and ENDP
  6773.    directives. The former declares the beginning of the procedure, and the
  6774.    latter declares the end.
  6775.  
  6776.    The PROC directive has the following syntax:
  6777.  
  6778.    label PROC [[NEAR|FAR]]
  6779.    statements
  6780.    RET [[constant]]
  6781.    label ENDP
  6782.  
  6783.    The label assigns a symbol to the procedure. The distance can be NEAR or
  6784.    FAR. Any RET instructions within the procedure automatically have the same
  6785.    distance (NEAR or FAR) as the procedure.
  6786.  
  6787.    The syntax shown here is always available. In addition, there is an
  6788.    extended PROC syntax available if you use .MODEL and specify a language.
  6789.    The extended PROC syntax is explained in Section 15.3.4, "Declaring
  6790.    Parameters with the PROC Directive."
  6791.  
  6792.    The ENDP directive labels the address where the procedure ends. Every
  6793.    procedure label must have a matching ENDP label to mark the end of the
  6794.    procedure. QuickAssembler generates an error message if it does not find
  6795.    an ENDP directive to match each PROC directive.
  6796.  
  6797.    When the PROC label definition is encountered, the assembler sets the
  6798.    label's value to the current value of the location counter and sets its
  6799.    type to NEAR or FAR. If the label has FAR type, the assembler also sets
  6800.    its segment value to that of the enclosing segment. If you have specified
  6801.    full segment definitions, the default distance is NEAR. If you are using
  6802.    simplified segment directives, the default distance is the distance
  6803.    associated with the declared memory model──that is, NEAR for small and
  6804.    compact models or FAR for medium, large, and huge models.
  6805.  
  6806.    The procedure label can be used in a CALL instruction to direct execution
  6807.    control to the first instruction of the procedure. Control can be
  6808.    transferred to a NEAR procedure label from any address in the same segment
  6809.    as the label. Control can be transferred to a FAR procedure label from an
  6810.    address in any segment.
  6811.  
  6812.    Procedure labels must be declared with the PUBLIC and EXTRN directives if
  6813.    they are located in one module but called from another module, as
  6814.    described in Chapter 8, "Creating Programs from Multiple Modules."
  6815.  
  6816.    Example
  6817.  
  6818.                call   task        ; Call procedure
  6819.                .
  6820.                .
  6821.                .
  6822.    task        PROC   NEAR        ; Start of procedure
  6823.                .
  6824.                .
  6825.                .
  6826.                ret
  6827.    task        ENDP               ; End of procedure
  6828.  
  6829.  
  6830.  6.4.4  Code Labels Defined with the LABEL Directive
  6831.  
  6832.    The LABEL directive provides an alternative method of defining code
  6833.    labels.
  6834.  
  6835.    Syntax
  6836.  
  6837.    name LABEL distance
  6838.  
  6839.    The name is the symbol name assigned to the label. The distance can be a
  6840.    type specifier, such as NEAR, FAR, or PROC. PROC means NEAR or FAR,
  6841.    depending on the default memory model, as described in Section 5.1.3,
  6842.    "Defining Basic Attributes of the Module." You can use the LABEL directive
  6843.    to define a second entry point into a procedure. FAR code labels can also
  6844.    be the destination of far jumps or of far calls that use the RETF
  6845.    instruction (see Section 15.3.2, "Defining Procedures").
  6846.  
  6847.    Example
  6848.  
  6849.    task        PROC   FAR         ; Main entry point
  6850.                .
  6851.                .
  6852.                .
  6853.    task1       LABEL  FAR         ; Secondary entry point
  6854.                .
  6855.                .
  6856.                .
  6857.                ret
  6858.    task        ENDP               ; End of procedure
  6859.  
  6860.  
  6861.  6.5  Defining and Initializing Data
  6862.  
  6863.    The data-definition directives enable you to allocate memory for data. At
  6864.    the same time, you can specify the initial values for the allocated data.
  6865.    Data can be specified as numbers, strings, or expressions that evaluate to
  6866.    constants. The assembler translates these constant values into binary
  6867.    bytes, words, or other units of data. The encoded data is written to the
  6868.    object file at assembly time.
  6869.  
  6870.  
  6871.  6.5.1  Variables
  6872.  
  6873.    Variables consist of one or more named data objects of a specified size.
  6874.  
  6875.    Syntax
  6876.  
  6877.    [[name]] directive initializer [[,initializer]]...
  6878.  
  6879.    The name is the symbol name assigned to the variable. If no name is
  6880.    assigned, the data is allocated; but the starting address of the variable
  6881.    has no symbolic name.
  6882.  
  6883.    The size of the variable is determined by directive. The directives that
  6884.    can be used to define single-item data objects are listed below:
  6885.  
  6886.    Directive           Meaning
  6887.    ──────────────────────────────────────────────────────────────────────────
  6888.    DB                  Defines byte
  6889.  
  6890.    DW                  Defines word (2 bytes)
  6891.  
  6892.    DD                  Defines doubleword (4 bytes)
  6893.  
  6894.    DQ                  Defines quadword (8 bytes)
  6895.  
  6896.    DT                  Defines 10-byte variable
  6897.  
  6898.  
  6899.    The optional initializer can be a constant, an expression that evaluates
  6900.    to a constant, or a question mark (?). The question mark is the symbol
  6901.    indicating that the value of the variable is undefined. You can define
  6902.    multiple values by using multiple initializers separated by commas, or by
  6903.    using the DUP operator, as explained in Section 6.5.2, "Arrays and
  6904.    Buffers."
  6905.  
  6906.    Simple data types can allocate memory for integers, strings, addresses, or
  6907.    real numbers.
  6908.  
  6909.  
  6910.  6.5.1.1  Integer Variables
  6911.  
  6912.    When defining an integer variable, you can specify an initial value as an
  6913.    integer constant or as a constant expression. QuickAssembler generates an
  6914.    error if you specify an initial value too large for the specified
  6915.    variable.
  6916.  
  6917.    Integer values for all sizes except 10-byte variables are stored in binary
  6918.    form. They can be interpreted as either signed or unsigned numbers. For
  6919.    instance, the hexadecimal value 0FFCD can be interpreted either as the
  6920.    signed number -51 or the unsigned number 65,485.
  6921.  
  6922.    The processor cannot tell the difference between signed and unsigned
  6923.    numbers. Some instructions are designed specifically for signed numbers.
  6924.    It is the programmer's responsibility to decide whether a value is to be
  6925.    interpreted as signed or unsigned, and then to use the appropriate
  6926.    instructions to handle the value correctly.
  6927.  
  6928.    Figure 6.1 shows various integer storage formats.
  6929.  
  6930.    ┌────────────────────────────────────────────────────────────────────────┐
  6931.    │ This figure can be found in Section 6.5.1.1 of the manual              │
  6932.    └────────────────────────────────────────────────────────────────────────┘
  6933.  
  6934.    The directives for defining integer variables are listed below with the
  6935.    sizes of integer they can define:
  6936.  
  6937.    Directive           Size of Directive
  6938.    ──────────────────────────────────────────────────────────────────────────
  6939.    DB (bytes)          Allocates unsigned numbers from 0 to 255 or signed
  6940.                        numbers from -128 to 127.
  6941.  
  6942.    DW (words)          Allocates unsigned numbers from 0 to 65,535 or signed
  6943.                        numbers from -32,768 to 32,767. The bytes of a word
  6944.                        integer are stored in the format shown in Figure 6.1.
  6945.                        Note that in assembler listings and in most debuggers
  6946.                        the bytes of a word are shown in the opposite
  6947.                        order──high byte first──since this is the way most
  6948.                        people think of numbers.
  6949.  
  6950.                        Word values can be used directly in 8086-family
  6951.                        instructions. They can also be loaded, used in
  6952.                        calculations, and stored with 8087-family
  6953.                        instructions.
  6954.  
  6955.    DD (doublewords)    Allocates unsigned numbers from 0 to 4,294,967,295 or
  6956.                        signed numbers from -2,147,483,648 to 2,147,483,647.
  6957.                        The words of a doubleword integer are stored in the
  6958.                        format shown in Figure 6.1.
  6959.  
  6960.                        These 32-bit values (called long integers) can be
  6961.                        loaded, used in calculations, and stored with
  6962.                        8087-family instructions. Some calculations can be
  6963.                        done on these numbers directly with 16-bit 8086-family
  6964.                        processors; others involve an indirect method of doing
  6965.                        calculations on each word separately (see Chapter 14,
  6966.                        "Doing Arithmetic and Bit Calculations").
  6967.  
  6968.    DQ (quadwords)      Allocates 64-bit integers. The doublewords of a
  6969.                        quadword integer are stored in the format shown in
  6970.                        Figure 6.1.
  6971.  
  6972.                        These values can be loaded, used in calculations, and
  6973.                        stored with 8087-family instructions. You must write
  6974.                        your own routines to use them with 16-bit 8086-family
  6975.                        processors.
  6976.  
  6977.    DT                  Allocates 10-byte (80-bit) integers if the D radix
  6978.                        specifier is used.
  6979.  
  6980.                        By default, DT allocates packed binary coded decimal
  6981.                        (BCD) numbers, as described in Section 6.5.1.2,
  6982.                        "Binary Coded Decimal Variables." If you define binary
  6983.                        10-byte integers, you must write your own routines to
  6984.                        use routines in calculations.
  6985.  
  6986.  
  6987.    Example
  6988.  
  6989.    integer     DB     16          ; Initialize byte to 16
  6990.    expression  DW     4*3         ; Initialize word to 12
  6991.    empty       DQ     ?           ; Allocate uninitialized long integer
  6992.                DB     1,2,3,4,5,6 ; Initialize six unnamed bytes
  6993.    long        DD     4294967295  ; Initialize double word to 4,294,967,295
  6994.    tb          DT     2345d       ; Initialize 10-byte binary integer
  6995.  
  6996.  
  6997.  6.5.1.2  Binary Coded Decimal Variables
  6998.  
  6999.    Binary coded decimal (BCD) numbers provide a method of doing calculations
  7000.    on large numbers without rounding errors. They are sometimes used in
  7001.    financial applications. There are two kinds: packed and unpacked.
  7002.  
  7003.    Unpacked BCD numbers are stored one digit to a byte, with the value in the
  7004.    lower four bits. They can be defined with the DB directive. For example,
  7005.    an unpacked BCD number could be defined and initialized as shown below:
  7006.  
  7007.    unpackedr   DB     1,5,8,2,5,2,9       ; Initialized to 9,252,851
  7008.    unpackedf   DB     9,2,5,2,8,5,1       ; Initialized to 9,252,851
  7009.  
  7010.    Whether least-significant digits can come either first or last depends on
  7011.    how you write the calculation routines that handle the numbers.
  7012.    Calculations with unpacked BCD numbers are discussed in Section 14.5.1.
  7013.  
  7014.    Packed BCD numbers are stored two digits to a byte, with one digit in the
  7015.    lower four bits and one in the upper four bits. The leftmost bit holds the
  7016.    sign (0 for positive or 1 for negative).
  7017.  
  7018.    Packed BCD variables can be defined with the DT directive as shown below:
  7019.  
  7020.    packed      DT     9252851             ; Allocate 9,252,851
  7021.  
  7022.    The 8087-family processors can do fast calculations with packed BCD
  7023.    numbers, as described in Chapter 17, "Calculating with a Math
  7024.    Coprocessor." The 8086-family processors can also do some calculations
  7025.    with packed BCD numbers, but the process is slower and more complicated.
  7026.    See Section 14.5.2 for details.
  7027.  
  7028.  
  7029.  6.5.1.3  String Variables
  7030.  
  7031.    Strings are normally initialized with the DB directive. The initializing
  7032.    value is specified as a string constant. Strings can also be initialized
  7033.    by specifying each value in the string. For example, the following
  7034.    definitions are equivalent:
  7035.  
  7036.    version1    DB     97,98,99            ; As ASCII values
  7037.    version2    DB     'a','b','c'         ; As characters
  7038.    version3    DB     "abc"               ; As a string
  7039.  
  7040.    One- and two-character strings can also be initialized with any of the
  7041.    other data-definition directives. The last (or only) character in the
  7042.    string is placed in the byte with the lowest address. Either 0 or the
  7043.    first character is placed in the next byte. The unused portion of such
  7044.    variables is filled with zeros.
  7045.  
  7046.    Examples
  7047.  
  7048.    function9   DB     'Hello',13,10,'$'   ; Use with DOS INT 21h
  7049.                                           ;   function 9
  7050.    asciiz      DB     "\ASM\TEST.ASM",0   ; Use as ASCIIZ string
  7051.  
  7052.    message     DB     "Enter file name: " ; Use with DOS INT 21h
  7053.    l_message   EQU    $-message           ;   function 40h
  7054.    a_message   EQU    OFFSET message
  7055.  
  7056.    str1        DB     "ab"                ; Stored as 61 62
  7057.    str2        DD     "ab"                ; Stored as 62 61 00 00
  7058.    str3        DD     "a"                 ; Stored as 61 00 00 00
  7059.  
  7060.  
  7061.  6.5.1.4  Real-Number Variables
  7062.  
  7063.    Real numbers must be stored in binary format. However, when initializing
  7064.    variables, you can specify decimal or hexadecimal constants and let the
  7065.    assembler automatically encode them into their binary equivalents.
  7066.    QuickAssembler can use two different binary formats for real numbers: IEEE
  7067.    or Microsoft Binary. You can specify the format by using directives (IEEE
  7068.    is the default).
  7069.  
  7070.    This section tells you how to initialize real-number variables, describes
  7071.    the two binary formats, and explains real-number encoding.
  7072.  
  7073.    Initializing and Allocating Real-Number Variables
  7074.  
  7075.    Real numbers can be defined by initializing them either with real-number
  7076.    constants or with encoded hexadecimal constants. The real-number
  7077.    designator (R) must follow numbers specified in encoded format.
  7078.  
  7079.    The directives for defining real numbers are listed below with the sizes
  7080.    of the numbers they can allocate:
  7081.  
  7082.    Directive           Size
  7083.    ──────────────────────────────────────────────────────────────────────────
  7084.    DD                  Allocates short (32-bit) real numbers in either the
  7085.                        IEEE or Microsoft Binary format.
  7086.  
  7087.    DQ                  Allocates long (64-bit) real numbers in either the
  7088.                        IEEE or Microsoft Binary format.
  7089.  
  7090.    DT                  Allocates temporary or 10-byte (80-bit) real numbers.
  7091.                        The format of these numbers is similar to the IEEE
  7092.                        format. They are always encoded the same regardless of
  7093.                        the real-number format. Their size is nonstandard and
  7094.                        incompatible with most Microsoft high-level languages.
  7095.                        Temporary-real format is provided for those who want
  7096.                        to initialize real numbers in the format used
  7097.                        internally by 8087-family processors.
  7098.  
  7099.  
  7100.    The 8086-family microprocessors do not have any instructions for handling
  7101.    real numbers. You must write your own routines, use a library that
  7102.    includes real-number calculation routines, or use a coprocessor. The
  7103.    8087-family coprocessors can load real numbers in the IEEE format; they
  7104.    can also use the values in calculations and store the results back to
  7105.    memory, as explained in Chapter 17, "Calculating with a Math
  7106.    Coprocessor."
  7107.  
  7108.    Examples
  7109.  
  7110.    shrt        DD      98.6                ; QuickAsm automatically encodes
  7111.    long        DQ      5.391E-4            ;   in current format
  7112.    ten_byte    DT      -7.31E7
  7113.    eshrt       DD      87453333r           ; 98.6 encoded in Microsoft
  7114.                                            ;   Binary format
  7115.    elong       DQ      3F41AA4C6F445B7Ar   ; 5.391E-4 encoded in IEEE format
  7116.  
  7117.    The real-number designator (R) used to specify encoded numbers is
  7118.    explained in Section 6.1.3, "Real-Number Constants."
  7119.  
  7120.    Selecting a Real-Number Format
  7121.  
  7122.    QuickAssembler can encode four-byte and eight-byte real numbers in two
  7123.    different formats: IEEE and Microsoft Binary. Your choice depends on the
  7124.    type of program you are writing. The four primary alternatives are listed
  7125.    below:
  7126.  
  7127.    1. If your program requires a coprocessor for calculations, you must use
  7128.       the IEEE format.
  7129.  
  7130.    2. Most high-level languages use the IEEE format. If you are writing
  7131.       modules that will be called from such a language, your program should
  7132.       use the IEEE format. All versions of the C, FORTRAN, and Pascal
  7133.       compilers sold by Microsoft and IBM use the IEEE format.
  7134.  
  7135.    3. If you are writing a module that will be called from early versions of
  7136.       Microsoft or IBM BASIC, your program should use the Microsoft Binary
  7137.       format. Versions that support only the Microsoft Binary format include:
  7138.  
  7139.       ■  Microsoft QuickBASIC through Version 2.01
  7140.  
  7141.       ■  Microsoft BASIC Compiler through Version 5.3
  7142.  
  7143.       ■  IBM BASIC Compiler through Version 2.0
  7144.  
  7145.       ■  Microsoft GW-BASIC(R) interpreter (all versions)
  7146.  
  7147.       ■  IBM BASICA interpreter (all versions)
  7148.  
  7149.       Microsoft QuickBASIC Version 3.0 supported both the Microsoft Binary
  7150.       and IEEE formats as options. Current and future versions of Microsoft
  7151.       QuickBASIC and the Microsoft and IBM BASIC compilers support only the
  7152.       IEEE format.
  7153.  
  7154.    4. If you are creating a stand-alone program that does not use a
  7155.       coprocessor, you can choose either format. The IEEE format is better
  7156.       for overall compatibility with high-level languages. The Microsoft
  7157.       Binary format may be necessary for compatibility with existing source
  7158.       code.
  7159.  
  7160.    ──────────────────────────────────────────────────────────────────────────
  7161.    NOTE  When you interface assembly-language modules with high-level
  7162.    languages, the real-number format only matters if you initialize
  7163.    real-number variables in the assembly module. If your assembly module does
  7164.    not use real numbers, or if all real numbers are initialized in the
  7165.    high-level-language module, the real-number format does not make any
  7166.    difference.
  7167.    ──────────────────────────────────────────────────────────────────────────
  7168.  
  7169.    By default, QuickAssembler assembles real-number data in the IEEE format.
  7170.    If you wish to use the Microsoft Binary format, you must put the .MSFLOAT
  7171.    directive at the start of your source file before initializing any
  7172.    real-number variables.
  7173.  
  7174.    Real-Number Encoding
  7175.  
  7176.    The IEEE format for encoding four- and eight-byte real numbers is
  7177.    illustrated in Figure 6.2. Although this figure places the
  7178.    most-significant bit first for illustration, low bytes actually appear
  7179.    first in memory.
  7180.  
  7181.    ┌────────────────────────────────────────────────────────────────────────┐
  7182.    │ This figure can be found in Section 6.5.1.4 of the manual              │
  7183.    └────────────────────────────────────────────────────────────────────────┘
  7184.  
  7185.    The parts of the real numbers are described below:
  7186.  
  7187.    1. Sign bit (0 for positive or 1 for negative) in the upper bit of the
  7188.       first byte.
  7189.  
  7190.    2. Exponent in the next bits in sequence (8 bits for short real number or
  7191.       11 bits for long real number).
  7192.  
  7193.    3. All except the first set bit of mantissa in the remaining bits of the
  7194.       variable. Since the first significant bit is known to be set, it need
  7195.       not be actually stored. The length is 23 bits for short real numbers
  7196.       and 52 bits for long real numbers.
  7197.  
  7198.    The Microsoft Binary format for encoding real numbers is illustrated in
  7199.    Figure 6.3.
  7200.  
  7201.    ┌────────────────────────────────────────────────────────────────────────┐
  7202.    │ This figure can be found in Section 6.5.1.4 of the manual              │
  7203.    └────────────────────────────────────────────────────────────────────────┘
  7204.  
  7205.    The three parts of real numbers are described below:
  7206.  
  7207.    1. Biased exponent (8 bits) in the high-address byte. The bias is 81H for
  7208.       short real numbers and 401H for long real numbers.
  7209.  
  7210.    2. Sign bit (0 for positive or 1 for negative) in the upper bit of the
  7211.       second-highest byte.
  7212.  
  7213.    3. All except the first set bit of mantissa in the remaining 7 bits of the
  7214.       second-highest byte and in the remaining bytes of the variable. Since
  7215.       the first significant bit is known to be set, it need not be actually
  7216.       stored. The length is 23 bits for short real numbers and 55 bits for
  7217.       long real numbers.
  7218.  
  7219.    QuickAssembler also supports the 10-byte temporary-real format used
  7220.    internally by 8087-family coprocessors. This format is similar to IEEE
  7221.    format. The size is nonstandard and is not used by Microsoft compilers or
  7222.    interpreters. Since the coprocessors can load and automatically convert
  7223.    numbers in the more standard 4-byte and 8-byte formats, the 10-byte format
  7224.    is seldom used in assembly-language programming.
  7225.  
  7226.    The temporary-real format for encoding real numbers is illustrated in
  7227.    Figure 6.4.
  7228.  
  7229.    ┌────────────────────────────────────────────────────────────────────────┐
  7230.    │ This figure can be found in Section 6.5.1.4 of the manual              │
  7231.    └────────────────────────────────────────────────────────────────────────┘
  7232.  
  7233.    The four parts of the real numbers are described below:
  7234.  
  7235.    1. Sign bit (0 for positive or 1 for negative) in the upper bit of the
  7236.       first byte.
  7237.  
  7238.    2. Exponent in the next bits in sequence (15 bits for 10-byte real).
  7239.  
  7240.    3. The integer part of mantissa in the next bit in sequence (bit 63).
  7241.  
  7242.    4. Remaining bits of mantissa in the remaining bits of the variable. The
  7243.       length is 63 bits.
  7244.  
  7245.    Notice that the 10-byte temporary-real format stores the integer part of
  7246.    the mantissa. This differs from the 4-byte and 8-byte formats, in which
  7247.    the integer part is implicit.
  7248.  
  7249.  
  7250.  6.5.2  Arrays and Buffers
  7251.  
  7252.    Arrays, buffers, and other data structures consisting of multiple data
  7253.    objects of the same size can be defined with the DUP operator. This
  7254.    operator can be used with any of the data-definition directives described
  7255.    in this chapter.
  7256.  
  7257.    Syntax
  7258.  
  7259.    count DUP (initialvalue[[,initialvalue]]...)
  7260.  
  7261.    The count sets the number of times to define initialvalue. The initial
  7262.    value can be any expression that evaluates to an integer value, a
  7263.    character constant, or another DUP operator. It can also be the undefined
  7264.    symbol (?) if there is no initial value.
  7265.  
  7266.    Multiple initial values must be separated by commas. If multiple values
  7267.    are specified within the parentheses, the sequence of values is allocated
  7268.    count times. For example, the statement
  7269.  
  7270.                DB     5 DUP ("Text ")
  7271.  
  7272.    allocates the string "Text " five times for a total of 25 bytes.
  7273.  
  7274.    DUP operators can be nested up to 17 levels. The initial value (or values)
  7275.    must always be placed within parentheses.
  7276.  
  7277.    Examples
  7278.  
  7279.    array       DD     10 DUP (1)                 ; 10 doublewords
  7280.                                                  ;   initialized to 1
  7281.  
  7282.    buffer      DB     256 DUP (?)                ; 256 byte buffer
  7283.  
  7284.    masks       DB     20 DUP (040h,020h,04h,02h) ; 80 byte buffer
  7285.                                                  ;   with bit masks
  7286.                DB     32 DUP ("I am here ")      ; 320 byte buffer with
  7287.                                                  ;   signature for debugging
  7288.    three_d     DD     5 DUP (5 DUP (5 DUP (0)))  ; 125 doublewords
  7289.                                                  ;   initialized to 0
  7290.  
  7291.    Note that QuickAssembler sometimes generates different object code when
  7292.    the DUP operator is used rather than when multiple values are given. For
  7293.    example, the statement
  7294.  
  7295.    test1       DB      ?,?,?,?,?  ; Indeterminate
  7296.  
  7297.    is "indeterminate." It causes QuickAssembler to write five zero-value
  7298.    bytes to the object file. The statement
  7299.  
  7300.    test2       DB      5 DUP (?)  ; Undefined
  7301.  
  7302.    is "undefined." It causes QuickAssembler to increase the offset of the
  7303.    next record in the object file by five bytes. Therefore, an object file
  7304.    created with the first statement will be larger than one created with the
  7305.    second statement.
  7306.  
  7307.    In most cases, the distinction between indeterminate and undefined
  7308.    definitions is trivial. The linker adjusts the offsets so that the same
  7309.    executable file is generated in either case. However, the difference is
  7310.    significant in segments with the COMMON combine type. If COMMON segments
  7311.    in two modules contain definitions for the same variable, one with an
  7312.    indeterminate value and one with an explicit value, the actual value in
  7313.    the executable file varies depending on link order. If the module with the
  7314.    indeterminate value is linked last, the 0 initialized for it overrides the
  7315.    explicit value. You can prevent this by always using undefined rather than
  7316.    indeterminate values in COMMON segments. For example, use the first of the
  7317.    following statements:
  7318.  
  7319.    test3       DB      1 DUP (?)  ; Undefined - doesn't initialize
  7320.    test4       DB      ?          ; Indeterminate - initializes 0
  7321.  
  7322.    If you use the undefined definition, the explicit value is always used in
  7323.    the executable file regardless of link order.
  7324.  
  7325.  
  7326.  6.5.3  Labeling Variables
  7327.  
  7328.    The LABEL directive can be used to define a variable of a given size at a
  7329.    specified location. It is useful if you want to refer to the same data as
  7330.    variables of different sizes.
  7331.  
  7332.    Syntax
  7333.  
  7334.    name LABEL type
  7335.  
  7336.    The name is the symbol assigned to the variable, and type is the variable
  7337.    size. The type can be any one of the following type specifiers: BYTE,
  7338.    WORD, DWORD, QWORD, or TBYTE. It can also be the name of a previously
  7339.    defined structure.
  7340.  
  7341.    Examples
  7342.  
  7343.    warray      LABEL   WORD       ; Access array as 50 words
  7344.    darray      LABEL   DWORD      ; Access same array as 25 doublewords
  7345.    barray      DB      100 DUP(?) ; Access same array as 100 bytes
  7346.  
  7347.  
  7348.  6.5.4  Pointer Variables
  7349.  
  7350.    The assembler lets you explicitly allocate pointers. A pointer (address)
  7351.    variable is either two or four bytes in size; consequently, any word or
  7352.    doubleword data definition can create a pointer variable. However,
  7353.    declaring pointer variables explicitly gives more accurate debugging
  7354.    information to the environment.
  7355.  
  7356.    Pointer-variable definitions have the following form:
  7357.  
  7358.    symbol [[DW | DD]] type PTR initialvalue
  7359.  
  7360.    The type can consist of the name of a record, structure, or one of the
  7361.    standard types described in Section 6.3, "Using Type Specifiers."
  7362.  
  7363.    Example
  7364.  
  7365.    string      DB  "from swerve of shore to bend of bay", 0
  7366.    pstring     DW  BYTE PTR string  ; Declares a near pointer to string.
  7367.    fpstring    DD  BYTE PTR string  ; Declares a far pointer to string.
  7368.  
  7369.    In this example, near (two-byte) and far (four-byte) pointers are declared
  7370.    and initialized to the value of a null terminated string. This is the
  7371.    format used in C language, and the pointer variables in the example could
  7372.    be used in C functions that process strings.
  7373.  
  7374.    Using an explicit pointer declaration generates debugging information,
  7375.    causing the variable to be viewed as a pointer during debugging.
  7376.    Consequently, the environment properly interprets the variable when you
  7377.    enter it as a Watch expression. No special syntax is required.
  7378.  
  7379.    This use of PTR is distinct from the use of PTR to alter the type of a
  7380.    variable during an instruction. The assembler uses the context of the
  7381.    program to determine which way you are using the PTR keyword.
  7382.  
  7383.  
  7384.  6.6  Setting the Location Counter
  7385.  
  7386.    As the assembler encounters labels and data declarations, it needs to know
  7387.    what address to assign. This function is fulfilled by the location
  7388.    counter, which indicates the offset address corresponding to the current
  7389.    line of source code. This value is generally equal to the value that IP
  7390.    will have at run time.
  7391.  
  7392.    The assembler increments the location counter as it processes each
  7393.    statement. However, you can set the location counter directly by using the
  7394.    ORG directive.
  7395.  
  7396.    Syntax
  7397.  
  7398.    ORG expression
  7399.  
  7400.    Subsequent code and data offsets begin at the new offset specified set by
  7401.    expression. The expression must resolve to a constant number. In other
  7402.    words, all symbols used in the expression must be known on the first pass
  7403.    of the assembler.
  7404.  
  7405.    ──────────────────────────────────────────────────────────────────────────
  7406.    NOTE  The value of the location counter, represented by the dollar sign
  7407.    ($), can be used in the expression, as described in Section 9.3, "Using
  7408.    the Location Counter."
  7409.    ──────────────────────────────────────────────────────────────────────────
  7410.  
  7411.    Example 1
  7412.  
  7413.    ; Labeling absolute addresses
  7414.  
  7415.    STUFF       SEGMENT AT 0        ; Segment has constant value 0
  7416.                ORG     410h        ; Offset has constant value 410h
  7417.    equipment   LABEL   WORD        ; Value at 0000:0410 labeled "equipment"
  7418.                ORG     417h        ; Offset has constant value 417h
  7419.    keyboard    LABEL   WORD        ; Value at 0000:0417 labeled "keyboard"
  7420.    STUFF       ENDS
  7421.  
  7422.                .CODE
  7423.                .
  7424.                .
  7425.                .
  7426.                ASSUME  ds:STUFF    ; Tell the assembler
  7427.                mov     ax,STUFF    ; Tell the processor
  7428.                mov     ds,ax
  7429.  
  7430.                mov     dx,equipment
  7431.                mov     keyboard,ax
  7432.  
  7433.    Example 1 illustrates one way of assigning symbolic names to absolute
  7434.    addresses.
  7435.  
  7436.    Example 2
  7437.  
  7438.    ; Format for .COM files
  7439.  
  7440.    _TEXT       SEGMENT
  7441.                ASSUME   cs:_TEXT,ds:_TEXT,ss:_TEXT,es:_TEXT
  7442.                ORG      100h        ; Skip 100h bytes of DOS header
  7443.  
  7444.    entry:      jmp      begin       ; Jump over data
  7445.    variable    DW       ?           ; Put more data here
  7446.                .
  7447.    begin:      .                    ; First line of code
  7448.                .                    ; Put more code here
  7449.    _TEXT       ENDS
  7450.                END      entry
  7451.  
  7452.    Example 2 illustrates how the ORG directive is used to initialize the
  7453.    starting execution point in .COM files.
  7454.  
  7455.  
  7456.  6.7  Aligning Data
  7457.  
  7458.    Some operations are more efficient when the variable used in the operation
  7459.    is lined up on a boundary of a particular size. The EVEN and ALIGN
  7460.    directives can be used to pad the object file so that the next variable is
  7461.    aligned on a specified boundary.
  7462.  
  7463.    Syntax 1
  7464.  
  7465.    EVEN
  7466.  
  7467.    Syntax 2
  7468.  
  7469.    ALIGN number
  7470.  
  7471.    The EVEN directive always aligns on the next even byte. The ALIGN
  7472.    directive aligns on the next byte that is a multiple of number. The number
  7473.    must be a power of 2. For example, use ALIGN 2 or EVEN to align on word
  7474.    boundaries, or use ALIGN 4 to align on doubleword boundaries.
  7475.  
  7476.    If the value of the location counter is not on the specified boundary when
  7477.    an ALIGN directive is encountered, the location counter is incremented to
  7478.    a value on the boundary. If the location counter is already on the
  7479.    boundary, the directive has no effect.
  7480.  
  7481.    When the assembler increments the location counter, it also pads the
  7482.    skipped memory locations by inserting certain values. If the segment is a
  7483.    data segment, the assembler always pads these locations with zeros. If the
  7484.    segment is a code segment, the assembler pads skipped memory locations
  7485.    with a two-byte no-op instruction (instruction that performed no
  7486.    operation) where possible:
  7487.  
  7488.                xchg  bx,bx
  7489.  
  7490.    This instruction, which assembles as 87D8 hexadecimal, does nothing, but
  7491.    it executes faster than two NOP instructions. Where there is no room for
  7492.    the two-byte no-op, the assembler inserts the one-byte NOP instruction.
  7493.  
  7494.    The ALIGN and EVEN directives give no efficiency improvements on
  7495.    processors that have an 8-bit data bus (such as the 8088). These
  7496.    processors always fetch data one byte at a time, regardless of the
  7497.    alignment. However, using EVEN can speed certain operation on processors
  7498.    that have a 16-bit data bus (such as the 8086), since the processor can
  7499.    fetch a word if the data is word aligned, but must do two memory fetches
  7500.    if the data is not word aligned.
  7501.  
  7502.    ──────────────────────────────────────────────────────────────────────────
  7503.    NOTE  The ALIGN directive is a new feature of recent versions of Microsoft
  7504.    assemblers, starting with 5.0. In previous versions, data could be word
  7505.    aligned by using the EVEN directive, but other alignments could not be
  7506.    specified.
  7507.  
  7508.    The EVEN directive should not be used in segments with BYTE align type.
  7509.    Similarly, the number specified with the ALIGN directive should be no
  7510.    greater than the size of the align type of the current segment (thus
  7511.    ensuring that number is a divisor of the align type of the segment).
  7512.    ──────────────────────────────────────────────────────────────────────────
  7513.  
  7514.    Example
  7515.  
  7516.                DOSSEG
  7517.                .MODEL  small,c
  7518.                .STACK  100h
  7519.                .DATA
  7520.                .
  7521.                .
  7522.                .
  7523.                ALIGN   2                   ; For faster data access
  7524.    stuff       DW      66,124,573,99,75
  7525.                .
  7526.                .
  7527.                .
  7528.                ALIGN   2                   ; For faster data access
  7529.    evenstuff   DW      ?,?,?,?,?
  7530.                .CODE
  7531.    start:      mov     ax,@data            ; Load segment location
  7532.                mov     ds,ax               ;   into DS
  7533.                mov     es,ax               ;   and ES registers
  7534.  
  7535.                mov     cx,5                ; Load count
  7536.                mov     si,OFFSET stuff     ; Point to source
  7537.                mov     di,OFFSET evenstuff ;   and destination
  7538.                ALIGN   2                   ; Align for faster loop access
  7539.    mloop:      lodsw                       ; Load a word
  7540.                inc     ax                  ; Make it even by incrementing
  7541.                and     ax,NOT 1            ;   and turning off first bit
  7542.                stosw                       ; Store
  7543.                loop    mloop               ; Again
  7544.                .
  7545.                .
  7546.                .
  7547.  
  7548.    In this example, the words at stuff and evenstuff are forced to word
  7549.    boundaries. This makes access to the data faster with processors that have
  7550.    a 16-bit data bus. Without this alignment, the initial data might start on
  7551.    an odd boundary and the processor would have to fetch half of each word at
  7552.    a time.
  7553.  
  7554.    Similarly, the alignment in the code segment speeds up repeated access to
  7555.    the code at the start of the loop. The sample code sacrifices program size
  7556.    in order to achieve moderate improvements on the 8086 and 80286. There is
  7557.    no speed advantage on the 8088.
  7558.  
  7559.  
  7560.  
  7561.  ────────────────────────────────────────────────────────────────────────────
  7562.  Chapter 7:  Using Structures and Records
  7563.  
  7564.  
  7565.    QuickAssembler can define and use two kinds of multifield variables:
  7566.    structures and records.
  7567.  
  7568.    "Structures" are templates for data objects made up of smaller data
  7569.    objects. A structure can be used to define structure variables, which are
  7570.    made up of smaller variables called fields. Fields within a structure can
  7571.    be different sizes, and each can be accessed individually.
  7572.  
  7573.    "Records" are templates for data objects whose bits can be described as
  7574.    groups of bits called fields. A record can be used to define record
  7575.    variables. Each bit field in a record variable can be used separately in
  7576.    constant operands or expressions. The processor cannot access bits
  7577.    individually at run time, but bit fields can be used with logical bit
  7578.    instructions to change bits indirectly.
  7579.  
  7580.    This chapter describes structures and records and tells how to use them.
  7581.  
  7582.  
  7583.  7.1  Structures
  7584.  
  7585.    A structure variable is a collection of data objects that can be accessed
  7586.    symbolically as a single data object. Objects within the structure can
  7587.    have different sizes and can be accessed symbolically.
  7588.  
  7589.    There are two steps in using structure variables:
  7590.  
  7591.    1. Declare a structure type. A structure type is a template for data. It
  7592.       declares the sizes and, optionally, the initial values for objects in
  7593.       the structure. By itself the structure type does not define any data.
  7594.       The structure type is used by QuickAssembler during assembly but is not
  7595.       saved as part of the object file.
  7596.  
  7597.    2. Define one or more variables having the structure type. For each
  7598.       variable defined, memory is allocated to the object file in the format
  7599.       declared by the structure type.
  7600.  
  7601.    The structure variable can then be used as an operand in assembler
  7602.    statements. The structure variable can be accessed as a whole by using the
  7603.    structure name, or individual fields can be accessed by using structure
  7604.    and field names.
  7605.  
  7606.  
  7607.  7.1.1  Declaring Structure Types
  7608.  
  7609.    The STRUC and ENDS directives mark the beginning and end of a type
  7610.    declaration for a structure.
  7611.  
  7612.    Syntax
  7613.  
  7614.    name STRUC
  7615.    fielddeclarations
  7616.    name ENDS
  7617.  
  7618.    The name declares the name of the structure type. It must be unique. The
  7619.    fielddeclarations declare the fields of the structure. Any number of field
  7620.    declarations may be given. They must follow the form of data definitions
  7621.    described in Section 6.5, "Defining and Initializing Data." Default
  7622.    initial values may be declared individually or with the DUP operator.
  7623.  
  7624.    The names given to fields must be unique within the source file where they
  7625.    are declared. When variables are defined, the field names will represent
  7626.    the offset from the beginning of the structure to the corresponding field.
  7627.  
  7628.    When declaring strings in a structure type, make sure the initial values
  7629.    are long enough to accommodate the largest possible string. Strings
  7630.    smaller than the field size can be placed in the structure variable, but
  7631.    larger strings will be truncated.
  7632.  
  7633.    A structure declaration can contain both field declarations and comments.
  7634.    Conditional-assembly statements are allowed in structure declarations; no
  7635.    other kinds of statements are allowed. Since the STRUC directive is not
  7636.    allowed inside structure declarations, structures cannot be nested.
  7637.  
  7638.    ──────────────────────────────────────────────────────────────────────────
  7639.    NOTE  The ENDS directive that marks the end of a structure has the same
  7640.    mnemonic as the ENDS directive that marks the end of a segment. The
  7641.    assembler recognizes the meaning of the directive from context. Make sure
  7642.    each SEGMENT directive and each STRUC directive has its own ENDS
  7643.    directive.
  7644.    ──────────────────────────────────────────────────────────────────────────
  7645.  
  7646.    Example
  7647.  
  7648.    student     STRUC                ; Structure for student records
  7649.    id          DW     ?             ; Field for identification #
  7650.    sname       DB     "Last, First Middle    "
  7651.    scores      DB     10 DUP (100)  ; Field for 10 scores
  7652.    student     ENDS
  7653.  
  7654.    Within the sample structure student, the fields id, sname, and scores have
  7655.    the offset values 0, 2, and 24, respectively.
  7656.  
  7657.  
  7658.  7.1.2  Defining Structure Variables
  7659.  
  7660.    A structure variable is a variable with one or more fields of different
  7661.    sizes. The sizes and initial values of the fields are determined by the
  7662.    structure type with which the variable is defined.
  7663.  
  7664.    Syntax
  7665.  
  7666.    [[name]] structurename <[[initialvalue [[,initialvalue]]...]]>
  7667.  
  7668.    The name is the name assigned to the variable. If no name is given, the
  7669.    assembler allocates space for the variable, but does not give it a
  7670.    symbolic name. The structurename is the name of a structure type
  7671.    previously declared by using the STRUC and ENDS directives.
  7672.  
  7673.    An initialvalue can be given for each field in the structure. Its type
  7674.    must not be incompatible with the type of the corresponding field. The
  7675.    angle brackets (< >) are required even if no initial value is given. If
  7676.    initial values are given for more than one field, the values must be
  7677.    separated by commas.
  7678.  
  7679.    If the DUP operator (see Section 6.5.2, "Arrays and Buffers") is used to
  7680.    initialize multiple structure variables, only the angle brackets and
  7681.    initial values, if given, need to be enclosed in parentheses. For example,
  7682.    you can define an array of structure variables as shown below:
  7683.  
  7684.    war         date    365 DUP (<,,1940>)
  7685.  
  7686.    You need not initialize all fields in a structure. If an initial value is
  7687.    left blank, the assembler automatically uses the default initial value of
  7688.    the field, which was originally determined by the structure type. If there
  7689.    is no default value, the field is undefined.
  7690.  
  7691.    Examples
  7692.  
  7693.    The following examples use the student type declared in the example in
  7694.    Section 7.1.1, "Declaring Structure Types":
  7695.  
  7696.    s1          student <>           ; Uses default values of type
  7697.  
  7698.  
  7699.    s2          student <1467,"White, Robert D.",>
  7700.                                     ; Override default values of first two
  7701.                                     ;   fields--use default value of third
  7702.  
  7703.    sarray      student 100 DUP (<>) ; Declare 100 student variables
  7704.                                     ;   with default initial values
  7705.  
  7706.    Note that you cannot initialize any structure field that has multiple
  7707.    values if this field was given a default initial value when the structure
  7708.    was declared. For example, assume the following structure declaration:
  7709.  
  7710.    stuff       STRUC
  7711.    buffer      DB     100 DUP (?)      ; Can't override
  7712.    crlf        DB     13,10            ; Can't override
  7713.    query       DB     'Filename: '     ; String <= can override
  7714.    endmark     DB     36               ; Can override
  7715.    stuff       ENDS
  7716.  
  7717.    The buffer and crlf fields cannot be overridden by initial values in the
  7718.    structure definition because they have multiple values. The query field
  7719.    can be overridden as long as the overriding string is no longer than query
  7720.    (10 bytes). A longer string would generate an error. The endmark field can
  7721.    be overridden by any byte value.
  7722.  
  7723.  
  7724.  7.1.3  Using Structure Operands
  7725.  
  7726.    Like other variables, structure variables can be accessed by name. Fields
  7727.    within structure variables can also be accessed by using the syntax shown
  7728.    below:
  7729.  
  7730.    Syntax
  7731.  
  7732.    variable.field
  7733.  
  7734.    The variable must be the name of a structure (or an operand that resolves
  7735.    to the address of a structure). The field must be the name of a field
  7736.    within that structure. The variable is separated from the field by a
  7737.    period. The period is discussed as a structure-field-name operator in
  7738.    Section 9.2.1.2.
  7739.  
  7740.    The address of a structure operand is the sum of the offsets of variable
  7741.    and field. The address is relative to the segment or group in which the
  7742.    variable is declared.
  7743.  
  7744.    Examples
  7745.  
  7746.    date        STRUC                       ; Declare structure
  7747.    month       DB      ?
  7748.    day         DB      ?
  7749.    year        DW      ?
  7750.    date        ENDS
  7751.  
  7752.                .DATA
  7753.    yesterday   date    <9,30,1987>         ; Declare structure
  7754.    today       date    <10,1,1987>         ;   variables
  7755.    tomorrow    date    <10,2,1987>
  7756.  
  7757.                .CODE
  7758.                .
  7759.                .
  7760.                .
  7761.                mov     al,yesterday.day    ; Use structure variables
  7762.                mov     ah,today.month      ;   as operands
  7763.                mov     tomorrow.year,dx
  7764.                mov     bx,OFFSET yesterday ; Load structure address
  7765.                mov     ax,[bx].month       ; Use as indirect operand
  7766.                .
  7767.                .
  7768.                .
  7769.  
  7770.  
  7771.  7.2  Records
  7772.  
  7773.    A record variable is a byte or word variable in which specific bit fields
  7774.    can be accessed symbolically. Bit fields within the record can have
  7775.    different sizes.
  7776.  
  7777.    There are two steps in declaring record variables:
  7778.  
  7779.    1. Declare a record type. A record type is a template for data. It
  7780.       declares the sizes and, optionally, the initial values for bit fields
  7781.       in the record. By itself, the record type does not define any data. The
  7782.       record type is used by Quick-Assembler during assembly but is not saved
  7783.       as part of the object file.
  7784.  
  7785.    2. Define one or more variables having the record type. For each variable
  7786.       defined, memory is allocated to the object file in the format declared
  7787.       by the type.
  7788.  
  7789.    The record variable can then be used as an operand in assembler
  7790.    statements. The record variable can be accessed as a whole by using the
  7791.    record name, or individual fields can be specified by using the record
  7792.    name and a field name combined with the field-name operator. A record type
  7793.    can also be used as a constant (immediate data).
  7794.  
  7795.  
  7796.  7.2.1  Declaring Record Types
  7797.  
  7798.    The RECORD directive declares a record type for an 8-bit or 16-bit record
  7799.    that contains one or more bit fields.
  7800.  
  7801.    Syntax
  7802.  
  7803.    recordname RECORD field [[,field]]...
  7804.  
  7805.    The recordname is the name of the record type to be used when creating the
  7806.    record. The field declares the name, width, and initial value for the
  7807.    field.
  7808.  
  7809.    The syntax for each field is shown below:
  7810.  
  7811.    Syntax
  7812.  
  7813.    fieldname:width[[=expression]]
  7814.  
  7815.    The fieldname is the name of a field in the record, width is the number of
  7816.    bits in the field, and expression is the initial (or default) value for
  7817.    the field.
  7818.  
  7819.    Any number of field combinations can be given for a record, as long as
  7820.    each is separated from its predecessor by a comma. The sum of the widths
  7821.    for all fields must not exceed 16 bits.
  7822.  
  7823.    The width must be a constant. If the total width of all declared fields is
  7824.    larger than eight bits, the assembler uses two bytes. Otherwise, only one
  7825.    byte is used.
  7826.  
  7827.    If expression is given, it declares the initial value for the field. An
  7828.    error message is generated if an initial value is too large for the width
  7829.    of its field. If the field is at least seven bits wide, you can use an
  7830.    ASCII character for expression. The expression must not contain a forward
  7831.    reference to any symbol.
  7832.  
  7833.    In all cases, the first field you declare goes into the most significant
  7834.    bits of the record. Successively declared fields are placed in the
  7835.    succeeding bits to the right. If the fields you declare do not total
  7836.    exactly 8 bits or exactly 16 bits, the entire record is shifted right so
  7837.    that the last bit of the last field is the lowest bit of the record.
  7838.    Unused bits in the high end of the record are initialized to 0.
  7839.  
  7840.    Example 1
  7841.  
  7842.    color       RECORD  blink:1,back:3,intense:1,fore:3
  7843.  
  7844.    Example 1 creates a byte record type color having four fields: blink,
  7845.    back, intense, and fore. The contents of the record type are shown below:
  7846.  
  7847.    ┌────────────────────────────────────────────────────────────────────────┐
  7848.    │ This figure can be found in Section 7.2.1 of the manual                │
  7849.    └────────────────────────────────────────────────────────────────────────┘
  7850.  
  7851.    Since no initial values are given, all bits are set to 0. Note that this
  7852.    is only a template maintained by the assembler. No data is created.
  7853.  
  7854.    Example 2
  7855.  
  7856.    cw          RECORD   r1:3=0,ic:1=0,rc:2=0,pc:2=3,r2:2=1,masks:6=63
  7857.  
  7858.    Example 2 creates a record type cw having six fields. Each record declared
  7859.    by using this type occupies 16 bits of memory. The bit diagram below shows
  7860.    the contents of the record type:
  7861.  
  7862.    ┌────────────────────────────────────────────────────────────────────────┐
  7863.    │ This figure can be found in Section 7.2.1 of the manual                │
  7864.    └────────────────────────────────────────────────────────────────────────┘
  7865.  
  7866.    Default values are given for each field. They can be used when data is
  7867.    declared for the record.
  7868.  
  7869.  
  7870.  7.2.2  Defining Record Variables
  7871.  
  7872.    A record variable is an 8-bit or 16-bit variable whose bits are divided
  7873.    into one or more fields.
  7874.  
  7875.    Syntax
  7876.  
  7877.    [[name]] recordname <[[initialvalue [[,initialvalue]]...]]>
  7878.  
  7879.    The name is the symbolic name of the variable. If no name is given, the
  7880.    assembler allocates space for the variable, but does not give it a
  7881.    symbolic name. The recordname is the name of a record type that was
  7882.    previously declared by using the RECORD directive.
  7883.  
  7884.    An initialvalue for each field in the record can be given as an integer, a
  7885.    character constant, or an expression that resolves to a value compatible
  7886.    with the size of the field. Angle brackets (< >) are required even if no
  7887.    initial value is given. If initial values for more than one field are
  7888.    given, the values must be separated by commas.
  7889.  
  7890.    If the DUP operator (see Section 6.5.2, "Arrays and Buffers") is used to
  7891.    initialize multiple record variables, only the angle brackets and initial
  7892.    values, if given, need to be enclosed in parentheses. For example, you can
  7893.    define an array of record variables as shown below:
  7894.  
  7895.    xmas        color   50 DUP (<1,2,0,4>)
  7896.  
  7897.    You do not have to initialize all fields in a record. If an initial value
  7898.    is left blank, the assembler automatically uses the default initial value
  7899.    of the field. This is declared by the record type. If there is no default
  7900.    value, each bit in the field is cleared.
  7901.  
  7902.    Sections 7.2.3, "Using Record Operands and Record Variables," and 7.2.4,
  7903.    "Record Operators," illustrate ways to use record data after it has been
  7904.    declared.
  7905.  
  7906.    Example 1
  7907.  
  7908.    color       RECORD  blink:1,back:3,intense:1,fore:3 ; Record declaration
  7909.    warning     color   <1,0,1,4>                       ; Record definition
  7910.  
  7911.    The definition above creates a variable named warning whose type is given
  7912.    by the record type color. The initial values of the fields in the variable
  7913.    are set to the values given in the record definition. The initial values
  7914.    would override the default record values, had any been given in the
  7915.    declaration. The contents of the record variable are shown below:
  7916.  
  7917.    ┌────────────────────────────────────────────────────────────────────────┐
  7918.    │ This figure can be found in Section 7.2.2 of the manual                │
  7919.    └────────────────────────────────────────────────────────────────────────┘
  7920.  
  7921.    Example 2
  7922.  
  7923.    color       RECORD  blink:1,back:3,intense:1,fore:3 ; Record declaration
  7924.    colors      color   16 DUP (<>)                     ; Record declaration
  7925.  
  7926.    Example 2 creates an array named colors containing 16 variables of type
  7927.    color. Since no initial values are given in either the declaration or the
  7928.    definition, the variables have undefined (0) values.
  7929.  
  7930.    Example 3
  7931.  
  7932.    cw          RECORD   r1:3=0,ic:1=0,rc:2=0,pc:2=3,r2:2=1,masks:6=63
  7933.    newcw       cw       <,,2,,,>
  7934.  
  7935.    Example 3 creates a variable named newcw with type cw. The default values
  7936.    set in the type declaration are used for all fields except the rc field.
  7937.    This field is set to 2. The contents of the variable are shown below:
  7938.  
  7939.    ┌────────────────────────────────────────────────────────────────────────┐
  7940.    │ This figure can be found in Section 7.2.2 of the manual                │
  7941.    └────────────────────────────────────────────────────────────────────────┘
  7942.  
  7943.  
  7944.  7.2.3  Using Record Operands and Record Variables
  7945.  
  7946.    A record operand refers to the value of a record type. It should not be
  7947.    confused with a record variable. A record operand is a constant; a record
  7948.    variable is a value stored in memory. A record operand can be used with
  7949.    the following syntax:
  7950.  
  7951.    Syntax
  7952.  
  7953.    recordname <[[value[[,value]]...]]>
  7954.  
  7955.    The recordname must be the name of a record type declared in the source
  7956.    file. The optional value is the value of a field in the record. If more
  7957.    than one value is given, each value must be separated by a comma. Values
  7958.    can include expressions or symbols that evaluate to constants. The
  7959.    enclosing angle brackets (<>) are required, even if no value is given. If
  7960.    no value for a field is given, the default value for that field is used.
  7961.  
  7962.    Example
  7963.  
  7964.                .DATA
  7965.    color       RECORD  blink:1,back:3,intense:1,fore:3 ; Record declaration
  7966.    window      color   <0,6,1,6>                       ; Record definition
  7967.  
  7968.                .CODE
  7969.                .
  7970.                .
  7971.                .
  7972.                mov     ah,color <0,3,0,2>              ; Load record operand
  7973.                                                        ;   (constant value 32h
  7974.                mov     bh,window                       ; Load record variable
  7975.                                                        ;   (memory value 6Eh)
  7976.  
  7977.    In this example, the record operand color <0,3,0,2> and the record
  7978.    variable warning are loaded into registers. The contents of the values are
  7979.    shown below:
  7980.  
  7981.    ┌────────────────────────────────────────────────────────────────────────┐
  7982.    │ This figure can be found in Section 7.2.3 of the manual                │
  7983.    └────────────────────────────────────────────────────────────────────────┘
  7984.  
  7985.  
  7986.  7.2.4  Record Operators
  7987.  
  7988.    The WIDTH and MASK operators are used exclusively with records to return
  7989.    constant values representing different aspects of previously declared
  7990.    records.
  7991.  
  7992.  
  7993.  7.2.4.1  The MASK Operator
  7994.  
  7995.    The MASK operator returns a bit mask for the bit positions in a record
  7996.    occupied by the given record field. A bit in the mask contains a 1 if that
  7997.    bit corresponds to a field bit. All other bits contain 0.
  7998.  
  7999.    Syntax
  8000.  
  8001.    MASK {recordfieldname | record}
  8002.  
  8003.    The recordfieldname may be the name of any field in a previously defined
  8004.    record. The record may be the name of any previously defined record. The
  8005.    NOT operator is sometimes used with the MASK operator to reverse the bits
  8006.    of a mask.
  8007.  
  8008.    Example
  8009.  
  8010.                .DATA
  8011.    color       RECORD  blink:1,back:3,intense:1,fore:3
  8012.    message     color   <0,5,1,1>
  8013.                .CODE
  8014.                .
  8015.                .
  8016.                .
  8017.                mov     ah,message           ; Load initial   0101 1001
  8018.                and     ah,NOT MASK back     ; Turn off   AND 1000 1111
  8019.                                             ; "back"         ---------
  8020.                                             ;                0000 1001
  8021.                or      ah,MASK blink        ; Turn on     OR 1000 0000
  8022.                                             ; "blink"        ---------
  8023.                                             ;                1000 1001
  8024.                xor     ah,MASK intense      ; Toggle     XOR 0000 1000
  8025.                                             ; "intense"      ---------
  8026.                                             ;                1000 0001
  8027.  
  8028.  
  8029.  7.2.4.2  The WIDTH Operator
  8030.  
  8031.    The WIDTH operator returns the width (in bits) of a record or record
  8032.    field.
  8033.  
  8034.    Syntax
  8035.  
  8036.    WIDTH {recordfieldname | record}
  8037.  
  8038.    The recordfieldname may be the name of any field defined in any record.
  8039.    The record may be the name of any defined record.
  8040.  
  8041.    Note that the width of a field is the number of bits assigned for that
  8042.    field; the value of the field is the starting position (from the right) of
  8043.    the field.
  8044.  
  8045.    Examples
  8046.  
  8047.                .DATA
  8048.    color       RECORD  blink:1,back:3,intense:1,fore:3
  8049.  
  8050.    wblink      EQU     WIDTH blink        ; "wblink"   = 1   "blink"   = 7
  8051.    wback       EQU     WIDTH back         ; "wback"    = 3   "back"    = 4
  8052.    wintense    EQU     WIDTH intense      ; "wintense" = 1   "intense" = 3
  8053.    wfore       EQU     WIDTH fore         ; "wfore"    = 3   "fore"    = 0
  8054.    wcolor      EQU     WIDTH color        ; "wcolor"   = 8
  8055.  
  8056.    prompt      color   <1,5,1,1>
  8057.  
  8058.                .CODE
  8059.                .
  8060.                .
  8061.                .
  8062.                IF      (WIDTH color) GE 8 ; If color is 16 bit, load
  8063.                mov     ax,prompt          ;   into 16-bit register
  8064.                ELSE                       ; else
  8065.                mov     al,prompt          ;   load into low 8-bit register
  8066.                xor     ah,ah              ;   and clear high 8-bit register
  8067.                ENDIF
  8068.  
  8069.  
  8070.  7.2.5  Using Record-Field Operands
  8071.  
  8072.    Record-field operands represent the location of a field in its
  8073.    corresponding record. The operand evaluates to the bit position of the
  8074.    low-order bit in the field and can be used as a constant operand. The
  8075.    field name must be from a previously declared record.
  8076.  
  8077.    Record-field operands are often used with the WIDTH and MASK operators, as
  8078.    described in Sections 7.2.4.1 and 7.2.4.2.
  8079.  
  8080.    Example
  8081.  
  8082.                .DATA
  8083.    color       RECORD  blink:1,back:3,intense:1,fore:3  ; Record declaration
  8084.    cursor      color   <1,5,1,1>                        ; Record definition
  8085.                .CODE
  8086.                .
  8087.                .
  8088.                .
  8089.  
  8090.    ; Rotate "back" of "cursor" without changing other values
  8091.  
  8092.                mov     al,cursor        ; Load value from memory
  8093.                mov     ah,al            ; Save a copy for work      1101 1001=
  8094.                and     al,NOT MASK back ; Mask out old bits     AND 1000 1111=
  8095.                                         ;   to save old cursor      ---------
  8096.                                         ;                           1000 1001=
  8097.                mov     cl,back          ; Load bit position
  8098.                shr     ah,cl            ; Shift to right            0000 1101=
  8099.                inc     ah               ; Increment                 0000 1110=
  8100.  
  8101.                shl     ah,cl            ; Shift left again          1110 0000=
  8102.                and     ah,MASK back     ; Mask off extra bits   AND 0111 0000=
  8103.                                         ;   to get new cursor       ---------
  8104.                                         ;                           0110 0000
  8105.                or      ah,al            ; Combine old and new    OR 1000 1001
  8106.                                         ;                           ---------
  8107.                mov     cursor,ah        ; Write back to memory      1110 1001
  8108.  
  8109.    This example illustrates several ways in which record fields can be used
  8110.    as operands and in expressions.
  8111.  
  8112.  
  8113.  
  8114.  ────────────────────────────────────────────────────────────────────────────
  8115.  Chapter 8:  Creating Programs from Multiple Modules
  8116.  
  8117.  
  8118.    Most medium and large assembly-language programs are created from several
  8119.    source files or modules. When several modules are used, the scope of
  8120.    symbols becomes important. This chapter discusses the scope of symbols and
  8121.    explains how to declare global symbols that can be accessed from any
  8122.    module. It also tells you how to specify a module that will be accessed
  8123.    from a library.
  8124.  
  8125.    Symbols, such as labels and variable names, can be either local or global
  8126.    in scope. By default, all symbols are local; they are specific to the
  8127.    source file in which they are defined. Symbols must be declared global if
  8128.    they must be accessed from modules other than the one in which they are
  8129.    defined.
  8130.  
  8131.    To declare symbols global, they must be declared public in the source
  8132.    module in which they are defined. They must also be declared external in
  8133.    any module that must access the symbol. If the symbol represents
  8134.    uninitialized data, it can be declared communal──meaning that the symbol
  8135.    is both public and external. The PUBLIC, EXTRN, and COMM directives are
  8136.    used to declare symbols public, external, and communal, respectively.
  8137.  
  8138.    ──────────────────────────────────────────────────────────────────────────
  8139.    NOTE  The term "local" often has a different meaning in assembly language
  8140.    than in many high-level languages. Local symbols in compiled languages are
  8141.    symbols that are known only within a procedure (called a function,
  8142.    routine, subprogram, or subroutine, depending on the language). You can
  8143.    use QuickAssembler to generate these kinds of variables, as explained in
  8144.    Section 15.3.6, "Creating Locals Automatically."
  8145.  
  8146.    By default, the assembler converts all lowercase letters in names declared
  8147.    with the PUBLIC, EXTRN, and COMM directives to uppercase letters before
  8148.    copying the name to the object file. To preserve lowercase names in public
  8149.    symbols, choose Preserve Case or Preserve Extrn from the Assembler Flags
  8150.    dialog box, or assemble with /Cx or /Cl on the QCL command line. This
  8151.    should be done when preparing assembler modules to be linked with modules
  8152.    from C and other case-sensitive languages.
  8153.    ──────────────────────────────────────────────────────────────────────────
  8154.  
  8155.  
  8156.  8.1  Declaring Symbols Public
  8157.  
  8158.    The PUBLIC directive is used to declare symbols public so that they can be
  8159.    accessed from other modules. If a symbol is not declared public, the
  8160.    symbol name is not written to the object file. The symbol has the value of
  8161.    its offset address during assembly, but the name and address are not
  8162.    available to the linker.
  8163.  
  8164.    If the symbol is declared public, its name is associated with its offset
  8165.    address in the object file. During linking, symbols in different
  8166.    modules──but with the same name──are resolved to a single address.
  8167.  
  8168.    Public symbol names are also used by some symbolic debuggers (such as
  8169.    SYMDEB) to associate addresses with symbols.
  8170.  
  8171.    Syntax
  8172.  
  8173.    PUBLIC declaration [[,declaration]]...
  8174.  
  8175.    Each declaration has the following syntax:
  8176.  
  8177.    [[lang]] name
  8178.  
  8179.    The optional lang field contains a language specifier that overrides the
  8180.    language specified by the .MODEL directive. With this statement, the
  8181.    language specifier determines naming conventions for the variable that it
  8182.    precedes. The specifier can be C, FORTRAN, Pascal, or BASIC. The C naming
  8183.    convention prefixes each variable with an underscore (_); the other
  8184.    conventions do not. If you specify lang with the .MODEL directive, all
  8185.    procedures are automatically public. However, you must use the PUBLIC
  8186.    directive for any data that you want to access from other modules.
  8187.  
  8188.    Note that using the C type specifier does not preserve case. You must
  8189.    choose one of the assembler flags or options that preserve case.
  8190.  
  8191.    The name must be the name of a variable, label, or numeric equate defined
  8192.    within the current source file. PUBLIC declarations can be placed anywhere
  8193.    in the source file. Equate names, if given, can only represent one-byte or
  8194.    two-byte integer or string values. Text macros (or text equates) cannot be
  8195.    declared public.
  8196.  
  8197.    Note that although absolute symbols can be declared public, aliases for
  8198.    public symbols may cause errors. For example, the following statements are
  8199.    illegal:
  8200.  
  8201.                PUBLIC  lines      ; Declare absolute symbol public
  8202.    lines       EQU     rows       ; Declare alias for lines
  8203.    rows        EQU     25         ; Illegal - Assign value to alias
  8204.  
  8205.    Example
  8206.  
  8207.                .MODEL  small,c
  8208.                PUBLIC  true,status,first,clear
  8209.    true        EQU     -1        ; Public constant
  8210.                .DATA
  8211.    status      DB      1         ; Public variable
  8212.                .CODE
  8213.                .
  8214.                .
  8215.                .
  8216.    first       LABEL   FAR       ; Public label
  8217.    clear       PROC              ; Procedure names are automatically public
  8218.                .                 ;   with .MODEL model, lang
  8219.                .
  8220.                .
  8221.    clear       ENDP
  8222.  
  8223.  
  8224.  8.2  Declaring Symbols External
  8225.  
  8226.    If a symbol undeclared in a module must be accessed by instructions in
  8227.    that module, it must be declared with the EXTRN directive.
  8228.  
  8229.    This directive tells the assembler not to generate an error, even though
  8230.    the symbol is not in the current module. The assembler assumes that the
  8231.    symbol occurs in another module. However, the symbol must actually exist
  8232.    and must be declared public in some module. Otherwise, the linker
  8233.    generates an error.
  8234.  
  8235.    Syntax
  8236.  
  8237.    EXTRN declaration [[,declaration]]...
  8238.  
  8239.    Each declaration has the following syntax:
  8240.  
  8241.    [[lang]]name:type
  8242.  
  8243.    The optional lang field contains a language specifier that overrides the
  8244.    language specified by the .MODEL directive. With this statement, the
  8245.    language specifier determines naming conventions for the variable that it
  8246.    precedes. The specifier can be C, FORTRAN, Pascal, or BASIC. The C naming
  8247.    convention prefixes each variable with an underscore (_); the other
  8248.    conventions do not.
  8249.  
  8250.    Note that using the C type specifier does not preserve case. You must
  8251.    choose one of the assembler flags or options that preserve case.
  8252.  
  8253.    The EXTRN directive defines an external variable, label, or symbol of the
  8254.    specified name and type. The type must match the type given to the item in
  8255.    its actual definition in some other module. It can be any one of the
  8256.    following:
  8257.  
  8258.    Description         Types
  8259.    ──────────────────────────────────────────────────────────────────────────
  8260.    Distance specifier  NEAR, FAR, or PROC
  8261.  
  8262.    Size specifier      BYTE, WORD, DWORD, QWORD, or TBYTE
  8263.  
  8264.    Absolute            ABS
  8265.  
  8266.  
  8267.    The ABS type is for symbols that represent constant numbers, such as
  8268.    equates declared with the EQU and = directives (see Section 11.1, "Using
  8269.    Equates").
  8270.  
  8271.    The PROC type represents the default type for a procedure. For programs
  8272.    that use simplified segment directives, the type of an external symbol
  8273.    declared with PROC will be NEAR for small or compact model, or FAR for
  8274.    medium, large, or huge model. Section 5.1.3, "Defining Basic Attributes
  8275.    of the Model," tells you how to declare the memory model using the .MODEL
  8276.    directive. If full segment definitions are used, the default type
  8277.    represented by PROC is always NEAR.
  8278.  
  8279.    Although the actual address of an external symbol is not determined until
  8280.    link time, the assembler assumes a default segment for the item, based on
  8281.    where the EXTRN directive is placed in the source code. Placement of EXTRN
  8282.    directives should follow these rules:
  8283.  
  8284.    ■  NEAR code labels (such as procedures) must be declared in the code
  8285.       segment from which they are accessed.
  8286.  
  8287.    ■  FAR code labels can be declared anywhere in the source code. It may be
  8288.       convenient to declare them in the code segment from which they are
  8289.       accessed if the label may be FAR in one context or NEAR in another.
  8290.  
  8291.    ■  Data must be declared in the segment in which it occurs. This may
  8292.       require that you define a dummy data segment for the external
  8293.       declaration.
  8294.  
  8295.    ■  Absolute symbols can be declared anywhere in the source code.
  8296.  
  8297.    Example 1
  8298.  
  8299.                EXTRN   max:ABS,act:FAR     ; Constant or FAR label anywhere
  8300.                DOSSEG
  8301.                .MODEL  small,c
  8302.                .STACK  100h
  8303.                .DATA
  8304.                EXTRN   nvar:BYTE           ; NEAR variable in near data
  8305.                .FARDATA
  8306.                EXTRN   fvar:WORD           ; FAR variable in far data
  8307.  
  8308.                .CODE
  8309.                .STARTUP
  8310.                EXTRN   task:PROC           ; PROC or NEAR in near code
  8311.                ASSUME  es:SEG fvar         ; Tell assembler
  8312.                mov     ax,SEG fvar         ; Tell processor that ES
  8313.                mov     es,ax               ;   has far data segment
  8314.  
  8315.                .
  8316.                .
  8317.                .
  8318.                mov     ah,nvar             ; Load external NEAR variable
  8319.                mov     bx,fvar             ; Load external FAR variable
  8320.                mov     cx,max              ; Load external constant
  8321.                call    task                ; Call procedure (NEAR or FAR)
  8322.                jmp     act                 ; Jump to FAR label
  8323.                END
  8324.  
  8325.    The example above shows how each type of external symbol could be declared
  8326.    and used in a small-model program that uses simplified segment directives.
  8327.    Notice the use of the PROC type specifier to make the external-procedure
  8328.    memory model independent. The jump and its external declaration are
  8329.    written so that they will be FAR regardless of the memory model. Using
  8330.    these techniques, you can change the memory model without breaking code.
  8331.  
  8332.    Example 2
  8333.  
  8334.                EXTRN   max:ABS,act:FAR     ; Constant or FAR label anywhere
  8335.    STACK       SEGMENT PARA STACK 'STACK'
  8336.                DB      100h DUP (?)
  8337.    STACK       ENDS
  8338.    _DATA       SEGMENT WORD PUBLIC 'DATA'
  8339.                EXTRN   nvar:BYTE           ; NEAR variable in near data
  8340.    _DATA       ENDS
  8341.    FAR_DATA    SEGMENT PARA 'FAR_DATA'
  8342.                EXTRN   fvar:WORD           ; FAR variable in far data
  8343.    FAR_DATA    ENDS
  8344.  
  8345.    DGROUP      GROUP   _DATA,STACK
  8346.    _TEXT       SEGMENT BYTE PUBLIC 'CODE'
  8347.                EXTRN   task:NEAR           ; NEAR procedure in near code
  8348.                ASSUME  cs:_TEXT,ds:DGROUP,ss:STACK
  8349.    start:      mov     ax,DGROUP           ; Load segment
  8350.                mov     ds,ax               ;   into DS
  8351.                ASSUME  es:SEG fvar         ; Tell assembler
  8352.                mov     ax,SEG fvar         ; Tell processor that ES
  8353.                mov     es,ax               ;   has far data segment
  8354.                .
  8355.                .
  8356.                .
  8357.                mov     ah,nvar             ; Load external NEAR variable
  8358.                mov     bx,fvar             ; Load external FAR variable
  8359.                mov     cx,max              ; Load external constant
  8360.                call    task                ; Call NEAR procedure
  8361.                jmp     act                 ; Jump to FAR label
  8362.    _TEXT       ENDS
  8363.                END     start
  8364.  
  8365.    Example 2 shows a fragment similar to the one in Example 1, but with full
  8366.    segment definitions. Notice that the types of code labels must be declared
  8367.    specifically. If you wanted to change the memory model, you would have to
  8368.    specifically change each external declaration and each call or jump.
  8369.  
  8370.  
  8371.  8.3  Using Multiple Modules
  8372.  
  8373.    The following source files illustrate a program that uses public and
  8374.    external declarations to access instruction labels. The program consists
  8375.    of two modules called hello and display.
  8376.  
  8377.    The hello module is the program's initializing module. Execution starts at
  8378.    the instruction labeled start in the hello module. After initializing the
  8379.    data segment, the program calls the procedure display in the display
  8380.    module, where a DOS call is used to display a message on the screen.
  8381.    Execution then returns to the address after the call in the hello module.
  8382.  
  8383.    The hello module is shown below:
  8384.  
  8385.                TITLE   hello
  8386.                DOSSEG
  8387.                .MODEL  small,c
  8388.                .STACK  256
  8389.  
  8390.                .DATA
  8391.                PUBLIC  message, lmessage
  8392.    message     DB      "Hello, world.",13,10
  8393.    lmessage    EQU     $ - message
  8394.  
  8395.                .CODE
  8396.                EXTRN   display:PROC       ; Declare in near code segment
  8397.                .STARTUP
  8398.                call    display            ; Call other module
  8399.                mov     ax,04C00h          ; Terminate with exit code 0
  8400.                int     21h                ; Call DOS
  8401.                END
  8402.  
  8403.    The display module is shown below:
  8404.  
  8405.                TITLE   display
  8406.                EXTRN   lmessage:ABS       ; Declare anywhere
  8407.                .MODEL  small
  8408.                .DATA
  8409.                EXTRN   message:BYTE       ; Declare in near data segment
  8410.  
  8411.                .CODE
  8412.    display     PROC
  8413.                mov     bx,1               ; File handle for standard output
  8414.                mov     cx,lmessage        ; Message length
  8415.                mov     dx,OFFSET message  ; Message address
  8416.                mov     ah,40h             ; Write function
  8417.                int     21h                ; Call DOS
  8418.                ret
  8419.  
  8420.    display     ENDP
  8421.                END
  8422.  
  8423.    The sample program is a variation of the HELLO.ASM program used in the
  8424.    examples in Chapter 4, "Writing Stand-Alone Assembly Programs," except
  8425.    that it uses an external procedure to display to the screen. Notice that
  8426.    all symbols defined in one module but used in another are declared PUBLIC
  8427.    in the defining module and declared EXTRN in the using module.
  8428.  
  8429.    For instance, message and lmessage are declared PUBLIC in the program
  8430.    HELLO.ASM and declared EXTRN in DISPLAY.ASM. The procedure display is
  8431.    declared EXTRN in HELLO.ASM. The symbol display is automatically public in
  8432.    the simplified segment version, but you would have to specifically declare
  8433.    it PUBLIC if you used full segments.
  8434.  
  8435.    To create an executable file for these modules, you can add both files to
  8436.    the environment's Program List dialog box. You can also assemble the
  8437.    modules with the following command line:
  8438.  
  8439.    QCL hello.asm display.asm
  8440.  
  8441.    The output is placed in the executable file HELLO.EXE.
  8442.  
  8443.    For each source module, QuickAssembler writes a module name to the object
  8444.    file. The module name is used by some debuggers and by the linker when it
  8445.    displays error messages. With QuickAssembler, the module name is always
  8446.    the base name of the source module file.
  8447.  
  8448.    For compatibility, QuickAssembler recognizes the NAME directive. However,
  8449.    NAME has no effect. Arguments to the directive are ignored.
  8450.  
  8451.  
  8452.  8.4  Declaring Symbols Communal
  8453.  
  8454.    Communal variables are uninitialized variables that are both public and
  8455.    external. They are often declared in include files.
  8456.  
  8457.    If a variable must be used by several assembly routines, you can declare
  8458.    the variable communal in an include file, and then include the file in
  8459.    each of the assembly routines. Although the variable is declared in each
  8460.    source module, it exists at only one address. Using a communal variable in
  8461.    an include file and including it in several source modules is an
  8462.    alternative to defining the variable and declaring it public in one source
  8463.    module and then declaring it external in other modules.
  8464.  
  8465.    If a variable is declared communal in one module and public in another,
  8466.    the public declaration takes precedence and the communal declaration has
  8467.    the same effect as an external declaration.
  8468.  
  8469.    Syntax
  8470.  
  8471.    COMM definition[[,definition]]...
  8472.  
  8473.    Each definition has the following syntax:
  8474.  
  8475.    [[NEAR | FAR]] [[lang]] label:size[[:count]]
  8476.  
  8477.    A communal variable can be NEAR or FAR. If neither is specified, the type
  8478.    will be that of the default memory model. If you use simplified segment
  8479.    directives, the default type is NEAR for small and medium models, or FAR
  8480.    for compact, large, and huge models. If you use full segment definitions,
  8481.    the default type is NEAR.
  8482.  
  8483.    The optional lang field can be C, BASIC, FORTRAN, or Pascal. The use of
  8484.    the C keyword turns on the C naming convention──the assembler prefixes the
  8485.    name of the variable with an underscore (_). The use of any of the other
  8486.    language types turns off the C naming convention, even if you specified C
  8487.    with the .MODEL directive. Note that the use of C does not preserve case.
  8488.    You must choose one of the assembler flags or options that preserve case.
  8489.  
  8490.    The label is the name of the variable. The size can be BYTE, WORD, DWORD,
  8491.    QWORD, TBYTE, or the name of a structure. The count is the number of
  8492.    elements. If no count is given, one element is assumed. Multiple variables
  8493.    can be defined with one COMM statement by separating each definition with
  8494.    a comma.
  8495.  
  8496.    ──────────────────────────────────────────────────────────────────────────
  8497.    NOTE  C variables declared outside functions (except static variables) are
  8498.    communal unless explicitly initialized; they are the same as
  8499.    assembly-language communal variables. If you are writing assembly-language
  8500.    modules for C, you can declare the same communal variables in C include
  8501.    files and in QuickAssembler include files.
  8502.    ──────────────────────────────────────────────────────────────────────────
  8503.  
  8504.    QuickAssembler cannot tell whether a communal variable has been used in
  8505.    another module. Allocation of communal variables is handled by LINK. As a
  8506.    result, communal variables have the following limitations that other
  8507.    variables declared in assembly language do not have:
  8508.  
  8509.    ■  Communal variables cannot be initialized. Under DOS, initial values are
  8510.       not guaranteed to be 0 or any other value. The variables can be used
  8511.       for data, such as file buffers, that is not given a value until run
  8512.       time.
  8513.  
  8514.    ■  Communal variables are not guaranteed to be allocated in the sequence
  8515.       in which they are declared. Assembly-language techniques that depend on
  8516.       the sequence and position in which data is defined should not be used
  8517.       with communal variables. For example, the following statements do not
  8518.       work:
  8519.  
  8520.  
  8521.                   COMM    wbuffer:WORD:128
  8522.       lbuffer     EQU     $ - buffer        ; "lbuffer" won't have desired val
  8523.  
  8524.       bbuffer     LABEL   BYTE              ; "bbuffer" won't have desired add
  8525.                   COMM    wbuffer:WORD:40
  8526.  
  8527.    ■  If a communal variable references a variable that is allocated and
  8528.       declared public inside a module, the variable has the segment of the
  8529.       allocated instance. If all references to the variable are communal, the
  8530.       variable will be placed in one of the segments described below.
  8531.  
  8532.       Near communal variables are placed in a segment called c_common, which
  8533.       is part of DGROUP. This group is created and initialized automatically
  8534.       if you use simplified segment directives. If you use full segment
  8535.       definitions, you must create a group called DGROUP and use the ASSUME
  8536.       directive to associate it with the DS register.
  8537.  
  8538.       Far communal variables are placed in a segment called FAR_BSS. This
  8539.       segment has combine type private and class type 'FAR_BSS'. This means
  8540.       that multiple segments with the same name can be created. Such segments
  8541.       cannot be accessed by name. They must be initialized indirectly using
  8542.       the SEG operator. For example, if a far communal variable (with word
  8543.       size) is called comvar, its segment can be initialized with the
  8544.       following lines:
  8545.  
  8546.                ASSUME  ds:SEG comvar      ; Tell the assembler
  8547.                mov     ax,SEG comvar      ; Tell the processor
  8548.                mov     ds,ax
  8549.                mov     bx,comvar          ; Use the variable
  8550.  
  8551.    Example 1
  8552.  
  8553.                .DATA
  8554.                COMM    temp:BYTE:128
  8555.  
  8556.    ASCIIZ      MACRO   address         ;; Name of address for string
  8557.                mov     temp,128        ;; Insert maximum length
  8558.                mov     dx,OFFSET temp  ;; Address of string buffer
  8559.                mov     ah,0Ah          ;; Get string
  8560.                int     21h
  8561.                mov     dl,temp[1]      ;; Get length of string
  8562.                xor     dh,dh
  8563.                mov     bx,dx
  8564.                mov     temp[bx+2],0    ;; Overwrite CR with null
  8565.    address     EQU     OFFSET temp+2
  8566.                ENDM
  8567.  
  8568.    Example 1 shows an include file that declares a buffer for temporary data.
  8569.    The buffer is then used in a macro in the same include file. An example of
  8570.    how the macro could be used in a source file is shown below:
  8571.  
  8572.                DOSSEG
  8573.                .MODEL  small,c
  8574.                INCLUDE communal.inc
  8575.                .STACK
  8576.                .DATA
  8577.    message     DB      "Enter file name: $"
  8578.                .CODE
  8579.                .STARTUP
  8580.                .
  8581.                .
  8582.                .
  8583.  
  8584.                mov     dx,OFFSET message      ; Load offset of file prompt
  8585.                mov     ah,09h                 ; Display prompt
  8586.                int     21h
  8587.  
  8588.                ASCIIZ  place                  ; Get file name and
  8589.                                               ;   return address as "place"
  8590.  
  8591.                mov     al,00000010b           ; Load access code
  8592.                mov     dx,place               ; Load address of ASCIIZ string
  8593.                mov     ah,3Dh                 ; Open the file
  8594.                int     21h
  8595.                .
  8596.                .
  8597.                .
  8598.  
  8599.    Note that once the macro is written, the user does not need to know the
  8600.    name of the temporary buffer or how it is used in the macro.
  8601.  
  8602.    Example 2
  8603.  
  8604.    date        STRUC
  8605.  
  8606.      month     DB   ?
  8607.      day       DB   ?
  8608.      year      DB   ?
  8609.  
  8610.    date        ENDS
  8611.  
  8612.                .DATA
  8613.                COMM   today:date
  8614.                .
  8615.                .
  8616.                .
  8617.  
  8618.    The example above uses the COMM directive to make the structure variable
  8619.    today a communal variable.
  8620.  
  8621.  
  8622.  8.5  Specifying Library Files
  8623.  
  8624.    The INCLUDELIB directive instructs the linker to link with a specified
  8625.    library file. If you are writing a program that calls library routines,
  8626.    you can use this directive to specify the library file in the assembly
  8627.    source file rather than in the LINK command line.
  8628.  
  8629.    Syntax
  8630.  
  8631.    INCLUDELIB libraryname
  8632.  
  8633.    The libraryname is written to the comment record of the object file. The
  8634.    Intel title for this record is COMENT. At link time, the linker reads this
  8635.    record and links with the specified library file.
  8636.  
  8637.    The libraryname must be a file name rather than a complete file
  8638.    specification. If you do not specify an extension, the default extension
  8639.    .LIB is assumed. LINK searches directories for the library file in the
  8640.    following order:
  8641.  
  8642.    1. The current directory
  8643.  
  8644.    2. Any directories given in the library field of the LINK command line
  8645.  
  8646.    3. Any directories listed in the LIB environment variable
  8647.  
  8648.    Example
  8649.  
  8650.                INCLUDELIB graphics
  8651.  
  8652.    This statement passes a message from QuickAssembler telling LINK to use
  8653.    library routines from the file GRAPHICS.LIB. If this statement is included
  8654.    in a source file called DRAW.ASM, the program might be linked with the
  8655.    following command line:
  8656.  
  8657.    LINK draw;
  8658.  
  8659.    Without the INCLUDELIB directive, the program would have to be linked with
  8660.    the following command line:
  8661.  
  8662.    LINK draw,,,graphics;
  8663.  
  8664.  
  8665.  
  8666.  ────────────────────────────────────────────────────────────────────────────
  8667.  Chapter 9:  Using Operands and Expressions
  8668.  
  8669.  
  8670.    Operands are the arguments that define values to be acted on by
  8671.    instructions or directives. Operands can be constants, variables,
  8672.    expressions, or keywords, depending on the instruction or directive and
  8673.    the context of the statement.
  8674.  
  8675.    A common type of operand is an expression. An expression consists of
  8676.    several operands that are combined to describe a value or memory location.
  8677.    Operators indicate the operations to be performed when combining the
  8678.    operands of an expression.
  8679.  
  8680.    Expressions are evaluated at assembly time. By using expressions, you can
  8681.    instruct the assembler to calculate values that would be difficult or
  8682.    inconvenient to calculate when you are writing source code.
  8683.  
  8684.    This chapter discusses operands, expressions, and operators as they are
  8685.    evaluated at assembly time. See Section 2.6, "Addressing Modes," for a
  8686.    discussion of the addressing modes that can be used to calculate operand
  8687.    values at run time. This chapter also discusses the location-counter
  8688.    operand, forward references, and strong typing of operands.
  8689.  
  8690.  
  8691.  9.1  Using Operands with Directives
  8692.  
  8693.    Each directive requires a specific type of operand. Most directives take
  8694.    string or numeric constants, or symbols or expressions that evaluate to
  8695.    such constants.
  8696.  
  8697.    The type of operand varies for each directive, but the operand must always
  8698.    evaluate to a value that is known at assembly time. This differs from
  8699.    instructions, whose operands may not be known at assembly time and may
  8700.    vary at run time. Operands used with instructions are discussed in Section
  8701.    2.6, "Addressing Modes."
  8702.  
  8703.    Some directives, such as those used in data declarations, accept labels or
  8704.    variables as operands. When a symbol that refers to a memory location is
  8705.    used as an operand to a directive, the symbol represents the address of
  8706.    the symbol rather than its contents. This is because the contents may
  8707.    change at run time and are therefore not known at assembly time.
  8708.  
  8709.    Example 1
  8710.  
  8711.                ORG     100h               ; Set address to 100h
  8712.    var         DB      10h                ; Address of "var" is 100h
  8713.                                           ; Value of "var" is 10h
  8714.    pvar        DW      var                ; Address of "pvar" is 101h
  8715.                                           ; Value of "pvar" is
  8716.                                           ;   address of "var" (100h)
  8717.  
  8718.    In Example 1, the operand of the DW directive in the third statement
  8719.    represents the address of var (100h) rather than its contents (10h). The
  8720.    address is relative to the start of the segment in which var is defined.
  8721.  
  8722.    Example 2
  8723.  
  8724.                TITLE   doit               ; String
  8725.    _TEXT       SEGMENT BYTE PUBLIC 'CODE' ; Key words
  8726.                INCLUDE \include\bios.inc  ; Pathname
  8727.                .RADIX  16                 ; Numeric constant
  8728.    tst         DW      a / b              ; Numeric expression
  8729.                PAGE    +                  ; Special character
  8730.    sum         EQU     x * y              ; Numeric expression
  8731.    here        LABEL   WORD               ; Type specifier
  8732.  
  8733.    Example 2 illustrates the different kinds of values that can be used as
  8734.    directive operands.
  8735.  
  8736.  
  8737.  9.2  Using Operators
  8738.  
  8739.    The assembler provides a variety of operators for combining, comparing,
  8740.    changing, or analyzing operands. Some operators work with integer
  8741.    constants, some with memory values, and some with both. Operators cannot
  8742.    be used with floating-point constants since QuickAssembler does not
  8743.    recognize real numbers in expressions.
  8744.  
  8745.    It is important to understand the difference between operators and
  8746.    instructions. Operators handle calculations of constant values that are
  8747.    known at assembly time. Instructions handle calculations of values that
  8748.    may not be known until run time. For example, the addition operator (+)
  8749.    handles assembly-time addition, while the ADD and ADC instructions handle
  8750.    run-time addition.
  8751.  
  8752.    This section describes the different kinds of operators used in
  8753.    assembly-language statements and gives examples of expressions formed with
  8754.    them. In addition to the operators described in this chapter, you can use
  8755.    the DUP operator (Section 6.5.2, "Arrays and Buffers"), the record
  8756.    operators (Section 7.2.4, "Record Operators"), and the macro operators
  8757.    (Section 11.4, "Using Macro Operators").
  8758.  
  8759.  
  8760.  9.2.1  Calculation Operators
  8761.  
  8762.    QuickAssembler provides the common arithmetic operators as well as several
  8763.    other operators for adding, shifting, or doing bit manipulations. The
  8764.    sections below describe operators that can be used for doing numeric
  8765.    calculations.
  8766.  
  8767.  
  8768.  9.2.1.1  Arithmetic Operators
  8769.  
  8770.    QuickAssembler recognizes a variety of arithmetic operators for common
  8771.    mathematical operations. Table 9.1 lists the arithmetic operators.
  8772.  
  8773.    Table 9.1 Arithmetic Operators
  8774.  
  8775.    Operator      Syntax                        Meaning
  8776.    ──────────────────────────────────────────────────────────────────────────
  8777.    +             +expression                   Positive (unary)
  8778.  
  8779.    -             -expression                   Negative (unary)
  8780.  
  8781.    *             expression1 * expression2     Multiplication
  8782.  
  8783.    /             expression1 / expression2     Integer division
  8784.  
  8785.    MOD           expression1 MOD expression2   Remainder (modulus)
  8786.  
  8787.    +             expression1 + expression2     Addition
  8788.  
  8789.    -             expression1 - expression2     Subtraction
  8790.  
  8791.    ──────────────────────────────────────────────────────────────────────────
  8792.  
  8793.  
  8794.    For all arithmetic operators except the addition operator (+) and the
  8795.    subtraction operator (-), the expressions operated on must be integer
  8796.    constants.
  8797.  
  8798.    The addition and subtraction operators can be used to add or subtract an
  8799.    integer constant and a memory operand. The result can be used as a memory
  8800.    operand.
  8801.  
  8802.    The subtraction operator can also be used to subtract one memory operand
  8803.    from another, but only if the operands refer to locations within the same
  8804.    segment. The result will be a constant, not a memory operand.
  8805.  
  8806.    ──────────────────────────────────────────────────────────────────────────
  8807.    NOTE  The unary plus and minus operators (used to designate positive or
  8808.    negative numbers) are not the same as the binary plus and minus operators
  8809.    (used to designate addition or subtraction). The unary plus and minus
  8810.    operators have a higher level of precedence, as described in Section
  8811.    9.2.5, "Operator Precedence."
  8812.    ──────────────────────────────────────────────────────────────────────────
  8813.  
  8814.    Example 1
  8815.  
  8816.    intgr       =       14  *  3           ; = 42
  8817.    intgr       =       intgr /  4         ; 42 / 4 = 10
  8818.    intgr       =       intgr  MOD  4      ; 10 mod 4 = 2
  8819.    intgr       =       intgr +  4         ; 2 + 4 = 6
  8820.    intgr       =       intgr -  3         ; 6 - 3 = 3
  8821.    intgr       =       -intgr - 8         ; -3 - 8 = -11
  8822.    intgr       =       -intgr - intgr     ; 11 - -11 = 22
  8823.  
  8824.    Example 1 illustrates arithmetic operators used in integer expressions.
  8825.  
  8826.    Example 2
  8827.  
  8828.                ORG     100h
  8829.    a           DB      ?                  ; Address is 100h
  8830.    b           DB      ?                  ; Address is 101h
  8831.    mem1        EQU     a + 5              ; mem1 = 100h + 5 = 105h
  8832.    mem2        EQU     a - 5              ; mem2 = 100h - 5 = 0FBh
  8833.    const       EQU     b - a              ; const = 101h - 100h = 1
  8834.  
  8835.    Example 2 illustrates arithmetic operators used in memory expressions.
  8836.  
  8837.  
  8838.  9.2.1.2  Structure-Field-Name Operator
  8839.  
  8840.    The structure-field-name operator (.) indicates addition. It is used to
  8841.    designate a field within a structure.
  8842.  
  8843.    Syntax
  8844.  
  8845.    variable.field
  8846.  
  8847.    The variable is a memory operand (usually a previously declared structure
  8848.    variable), and field is the name of a field within the structure. See
  8849.    Section 7.1, "Structures," for more information.
  8850.  
  8851.    Example
  8852.  
  8853.                .DATA
  8854.    date        STRUC                      ; Declare structure
  8855.      month     DB      ?
  8856.      day       DB      ?
  8857.      year      DW      ?
  8858.    date        ENDS
  8859.    yesterday   date    <12,31,1987>       ; Define structure variables
  8860.    today       date    <1,1,1988>
  8861.  
  8862.                .CODE
  8863.                .
  8864.                .
  8865.                .
  8866.                mov     bh,yesterday.day   ; Load structure variable
  8867.                mov     bx,OFFSET today    ; Load structure variable address
  8868.                inc     [bx].year          ; Use in indirect memory operand
  8869.  
  8870.  
  8871.  9.2.1.3  Index Operator
  8872.  
  8873.    The index operator ([ ]) indicates addition. It is similar to the addition
  8874.    (+) operator. When used with a register, the index operator also indicates
  8875.    that the operand is an indirect memory operand rather than a
  8876.    register-direct operand.
  8877.  
  8878.    Syntax
  8879.  
  8880.    [[expression1]][expression2]
  8881.  
  8882.    In most cases expression1 is simply added to expression2. The limitations
  8883.    of the addition operator for adding memory operands also apply to the
  8884.    index operator. For example, two direct memory operands cannot be added.
  8885.    The expression label1[label2] is illegal if both are memory operands.
  8886.  
  8887.    The index operator has an extended function in specifying indirect memory
  8888.    operands. Section 2.6.4 explains the use of indirect memory operands. The
  8889.    index brackets must be outside the register or registers that specify the
  8890.    indirect displacement. However, any of the three operators that indicate
  8891.    addition (the addition operator, the index operator, or the
  8892.    structure-field-name operator) may be used for multiple additions within
  8893.    the expression.
  8894.  
  8895.    For example, the following statements are equivalent:
  8896.  
  8897.               mov     ax,table[bx][di]
  8898.               mov     ax,table[bx+di]
  8899.               mov     ax,[table+bx+di]
  8900.               mov     ax,[table][bx][di]
  8901.  
  8902.    The following statements are illegal because the index operator does not
  8903.    enclose the registers that specify indirect displacement:
  8904.  
  8905.                mov     ax,table+bx+di     ; Illegal - no index operator
  8906.                mov     ax,[table]+bx+di   ; Illegal - registers not
  8907.                                           ;   inside index operator
  8908.  
  8909.    The index operator is typically used to index elements of a data object,
  8910.    such as variables in an array or characters in a string.
  8911.  
  8912.    Example 1
  8913.  
  8914.                mov     al,string[3]       ; Get 4th element of string
  8915.                add     ax,array[4]        ; Add 5th element of array
  8916.                mov     string[7],al       ; Load into 8th element of string
  8917.  
  8918.    Example 1 illustrates the index operator used with direct memory operands.
  8919.  
  8920.    Example 2
  8921.  
  8922.                mov     ax,[bx]            ; Get element BX points to
  8923.                add     ax,array[si]       ; Add element SI points to
  8924.                mov     string[di],al      ; Load element DI points to
  8925.                cmp     cx,table[bx][di]   ; Compare to element BX and DI point
  8926.  
  8927.    Example 2 illustrates the index operator used with indirect memory
  8928.    operands.
  8929.  
  8930.  
  8931.  9.2.1.4  Shift Operators
  8932.  
  8933.    The SHR and SHL operators can be used to shift bits in constant values.
  8934.    Both perform logical shifts. Bits on the right for SHL and on the left for
  8935.    SHR are zero-filled as their contents are shifted out of position.
  8936.  
  8937.    Syntax
  8938.  
  8939.    expression SHR count
  8940.    expression SHL count
  8941.  
  8942.    The expression is shifted right or left by count number of bits. Bits
  8943.    shifted off either end of the expression are lost. If count is greater
  8944.    than or equal to 16, the result is 0.
  8945.  
  8946.    Do not confuse the SHR and SHL operators with the processor instructions
  8947.    having the same names. The operators work on integer constants only at
  8948.    assembly time. The processor instructions work on register or memory
  8949.    values at run time. The assembler can tell the difference between
  8950.    instructions and operands from context.
  8951.  
  8952.    Examples
  8953.  
  8954.    mov     ax,01110111b SHL 3 ; Load 01110111000b
  8955.    mov     ah,01110111b SHR 3 ; Load 01110b
  8956.  
  8957.  
  8958.  9.2.1.5  Bitwise Logical Operators
  8959.  
  8960.    The bitwise operators perform logical operations on each bit of an
  8961.    expression. The expressions must resolve to constant values. Table 9.2
  8962.    lists the logical operators and their meanings.
  8963.  
  8964.    Table 9.2 Logical Operators
  8965.  
  8966.    Operator      Syntax                        Meaning
  8967.    ──────────────────────────────────────────────────────────────────────────
  8968.    NOT           NOT expression                Bitwise complement
  8969.  
  8970.    AND           expression1 AND expression2   Bitwise AND
  8971.  
  8972.    OR            expression1 OR expression2    Bitwise inclusive OR
  8973.  
  8974.    XOR           expression1 XOR expression2   Bitwise exclusive XOR
  8975.  
  8976.    ──────────────────────────────────────────────────────────────────────────
  8977.  
  8978.  
  8979.    Do not confuse the NOT, AND, OR, and XOR operators with the processor
  8980.    instructions having the same names. The operators work on integer
  8981.    constants only at assembly time. The processor instructions work on
  8982.    register or memory values at run time. The assembler can tell the
  8983.    difference between instructions and operands from context.
  8984.  
  8985.    ──────────────────────────────────────────────────────────────────────────
  8986.    NOTE  Although calculations on expressions using the AND, OR, and XOR
  8987.    operators are done using 17-bit numbers, the results are truncated to 16
  8988.    bits.
  8989.    ──────────────────────────────────────────────────────────────────────────
  8990.  
  8991.    Examples
  8992.  
  8993.         mov     ax,NOT 11110000b            ; Load 1111111100001111b
  8994.         mov     ah,NOT 11110000b            ; Load 00001111b
  8995.         mov     ah,01010101b AND 11110000b  ; Load 01010000b
  8996.         mov     ah,01010101b OR  11110000b  ; Load 11110101b
  8997.         mov     ah,01010101b XOR 11110000b  ; Load 10100101b
  8998.  
  8999.  
  9000.  9.2.2  Relational Operators
  9001.  
  9002.    The relational operators compare two expressions and return true (-1) if
  9003.    the condition specified by the operator is satisfied, or false (0) if it
  9004.    is not. The expressions must resolve to constant values. Relational
  9005.    operators are typically used with conditional directives. Table 9.3 lists
  9006.    the operators and the values they return if the specified condition is
  9007.    satisfied.
  9008.  
  9009.    Table 9.3 Relational Operators
  9010.  
  9011.    Operator      Syntax                        Returned Value
  9012.    ──────────────────────────────────────────────────────────────────────────
  9013.    EQ            expression1 EQ expression2    True if expressions are equal
  9014.  
  9015.    NE            expression1 NE expression2    True if expressions are not
  9016.                                                equal
  9017.  
  9018.    LT            expression1 LT expression2    True if left expression is
  9019.                                                less than right
  9020.  
  9021.    LE            expression1 LE expression2    True if left expression is
  9022.                                                less than or equal to right
  9023.  
  9024.    GT            expression1 GT expression2    True if left expression is
  9025.                                                greater than right
  9026.  
  9027.    GE            expression1 GE expression2    True if left expression is
  9028.                                                greater than or equal to right
  9029.  
  9030.    ──────────────────────────────────────────────────────────────────────────
  9031.  
  9032.  
  9033.    Note that the EQ and NE operators treat their arguments as 16-bit numbers.
  9034.    Numbers specified with the 16th bit set are considered negative. For
  9035.    example, the expression -1 EQ OFFFFh is true, but the expression -1 NE
  9036.    OFFFFh is false.
  9037.  
  9038.    The LT, LE, GT, and GE operators treat their arguments as 17-bit numbers,
  9039.    in which the 17th bit specifies the sign. For example, OFFFFh is 65,535,
  9040.    not -1. The expression 1 GT -1 is true, but the expression 1 GT OFFFFh is
  9041.    false.
  9042.  
  9043.    Examples
  9044.  
  9045.            mov     ax,4 EQ 3  ; Load false( 0)
  9046.            mov     ax,4 NE 3  ; Load true  (-1)
  9047.            mov     ax,4 LT 3  ; Load false( 0)
  9048.            mov     ax,4 LE 3  ; Load false( 0)
  9049.            mov     ax,4 GT 3  ; Load true (-1)
  9050.            mov     ax,4 GE 3  ; Load true(-1)
  9051.  
  9052.  
  9053.  9.2.3  Segment-Override Operator
  9054.  
  9055.    The segment-override operator (:) forces the address of a variable or
  9056.    label to be computed relative to a specific segment.
  9057.  
  9058.    Syntax
  9059.  
  9060.    segment:expression
  9061.  
  9062.    The segment can be specified in several ways. It can be one of the segment
  9063.    registers: CS, DS, SS, or ES. It can also be a segment or group name. In
  9064.    this case, the name must have been previously defined with a SEGMENT or
  9065.    GROUP directive and assigned to a segment register with an ASSUME
  9066.    directive. The expression can be a constant, expression, or a SEG
  9067.    expression. See Section 9.2.4.5 for more information on the SEG operator.
  9068.  
  9069.    Note that when a segment override is given with an indexed operand, the
  9070.    segment must be specified outside the index operators. For example,
  9071.    es:[di] is correct, but [es:di] generates an error.
  9072.  
  9073.    Examples
  9074.  
  9075.                mov     ax,ss:[bx+4]       ; Override default assume (DS)
  9076.                mov     al,es:082h         ; Load from ES
  9077.  
  9078.                ASSUME  ds:FAR_DATA        ; Tell the assembler and
  9079.                mov     bx,FAR_DATA:count  ;   load from a far segment
  9080.  
  9081.    As shown in the last two statements, a segment override with a segment
  9082.    name is not enough if no segment register is assumed for the segment name.
  9083.    You must use the ASSUME directive to assign a segment register, as
  9084.    explained in Section 5.4, "Associating Segments with Registers."
  9085.  
  9086.  
  9087.  9.2.4  Type Operators
  9088.  
  9089.    This section describes the assembler operators that specify or analyze the
  9090.    types of memory operands and other expressions.
  9091.  
  9092.  
  9093.  9.2.4.1  PTR Operator
  9094.  
  9095.    The PTR operator specifies the type for a variable or label.
  9096.  
  9097.    Syntax
  9098.  
  9099.    type PTR expression
  9100.  
  9101.    The operator forces expression to be treated as having type. The
  9102.    expression can be any operand. The type can be BYTE, WORD, DWORD, QWORD,
  9103.    or TBYTE for memory operands. It can be NEAR, FAR, or PROC for labels.
  9104.  
  9105.    The PTR operator is typically used with forward references to define
  9106.    explicitly what size or distance a reference has. If it is not used, the
  9107.    assembler assumes a default size or distance for the reference. See
  9108.    Section 9.4 for more information on forward references.
  9109.  
  9110.    The PTR operator is also used to enable instructions to access variables
  9111.    in ways that would otherwise generate errors. For example, you could use
  9112.    the PTR operator to access the high-order byte of a WORD size variable.
  9113.    The PTR operator is required for FAR calls and jumps to forward-referenced
  9114.    labels.
  9115.  
  9116.    Example 1
  9117.  
  9118.                .DATA
  9119.    stuff       DD      ?
  9120.    buffer      DB      20 DUP (?)
  9121.  
  9122.                .CODE
  9123.                .
  9124.                .
  9125.                .
  9126.                call    FAR PTR task            ; Call a far procedure
  9127.                jmp     FAR PTR place           ; Jump far
  9128.  
  9129.                mov     bx,WORD PTR stuff[0]    ; Load a word from a
  9130.                                                ;   doubleword variable
  9131.                add     ax,WORD PTR buffer[bx]  ; Add a word from a byte variab
  9132.  
  9133.    The PTR operator can be used to specify the size of an indirect register
  9134.    operand for a CALL or JMP instruction. However, the size cannot be
  9135.    specified with NEAR or FAR. Use WORD or DWORD instead. Examples are shown
  9136.    below:
  9137.  
  9138.    Example 2
  9139.  
  9140.              jmp     WORD PTR [bx]           ; Legal near jump
  9141.              call    NEAR PTR [bx]           ; Illegal near call
  9142.              call    DWORD PTR [bx]          ; Legal far call
  9143.              jmp     FAR PTR [bx]            ; Illegal far jump
  9144.  
  9145.    This limitation only applies to indirect register operands. NEAR or FAR
  9146.    can be applied to operands associated with labels, as shown in Example 1.
  9147.    Furthermore, use NEAR or FAR with an indirect operand that combines a
  9148.    register with a label.
  9149.  
  9150.  
  9151.  9.2.4.2  SHORT Operator
  9152.  
  9153.    The SHORT operator sets the type of a specified label to SHORT. Short
  9154.    labels can be used in JMP instructions whenever the distance from the
  9155.    label to the instruction is less than 128 bytes.
  9156.  
  9157.    Syntax
  9158.  
  9159.    SHORT label
  9160.  
  9161.    Instructions using short labels are a byte smaller than identical
  9162.    instructions using the default near labels. See Section 9.4.1, "Forward
  9163.    References to Labels," for information on using the SHORT operator with
  9164.    jump instructions.
  9165.  
  9166.    Example
  9167.  
  9168.                jmp     again              ; Jump 128 bytes or more
  9169.                .
  9170.                .
  9171.                .
  9172.                jmp     SHORT again        ; Jump less than 128 bytes
  9173.                .
  9174.                .
  9175.                .
  9176.    again:
  9177.  
  9178.  
  9179.  9.2.4.3  THIS Operator
  9180.  
  9181.    The THIS operator creates an operand whose offset and segment values are
  9182.    equal to the current location-counter value and whose type is specified by
  9183.    the operator.
  9184.  
  9185.    Syntax
  9186.  
  9187.    THIS type
  9188.  
  9189.    The type can be BYTE, WORD, DWORD, QWORD, or TBYTE for memory operands. It
  9190.    can be NEAR, FAR, or PROC for labels.
  9191.  
  9192.    The THIS operator is typically used with the EQU or equal-sign (=)
  9193.    directive to create labels and variables. The result is similar to using
  9194.    the LABEL directive.
  9195.  
  9196.    Example
  9197.  
  9198.    tag1        EQU     THIS BYTE  ; Both represent the same variable
  9199.    tag2        LABEL   BYTE
  9200.  
  9201.    check1      EQU     THIS NEAR  ; All represent the same address
  9202.    check2      LABEL   NEAR
  9203.    check3:
  9204.    check4      PROC    NEAR
  9205.    check4      ENDP
  9206.  
  9207.  
  9208.  9.2.4.4  HIGH and LOW Operators
  9209.  
  9210.    The HIGH and LOW operators return the high and low bytes, respectively, of
  9211.    an expression.
  9212.  
  9213.    Syntax
  9214.  
  9215.    HIGH expression
  9216.    LOW expression
  9217.  
  9218.    The HIGH operator returns the high-order eight bits of expression; the LOW
  9219.    operator returns the low-order eight bits. The expression must evaluate to
  9220.    a constant. You cannot use the HIGH and LOW operators on the contents of a
  9221.    memory operand since the contents may change at run time.
  9222.  
  9223.    Examples
  9224.  
  9225.    stuff       EQU     0ABCDh
  9226.                mov     ah,HIGH stuff      ; Load 0ABh
  9227.                mov     al,LOW stuff       ; Load 0CDh
  9228.  
  9229.    The HIGH and LOW operators work reliably only with constants and with
  9230.    offsets to external symbols. HIGH and LOW operations are not supported for
  9231.    offsets to local symbols.
  9232.  
  9233.  
  9234.  9.2.4.5  SEG Operator
  9235.  
  9236.    The SEG operator returns the segment address of an expression.
  9237.  
  9238.    Syntax
  9239.  
  9240.    SEG expression
  9241.  
  9242.    The expression can be any label, variable, segment name, group name, or
  9243.    other memory operand. The SEG operator cannot be used with constant
  9244.    expressions. The returned value can be used as a memory operand.
  9245.  
  9246.    Example
  9247.  
  9248.                .DATA
  9249.    var         DB      ?
  9250.                .CODE
  9251.                .
  9252.                .
  9253.                .
  9254.                ASSUME  ds:SEG var         ; Assume segment of variable
  9255.                mov     ax,SEG var         ; Get address of segment
  9256.                mov     ds,ax              ;   where variable is declared
  9257.  
  9258.  
  9259.  9.2.4.6  OFFSET Operator
  9260.  
  9261.    The OFFSET operator returns the offset address of an expression.
  9262.  
  9263.    Syntax
  9264.  
  9265.    OFFSET expression
  9266.  
  9267.    The expression can be any label, variable, or other direct memory operand.
  9268.    Constant expressions return meaningless values. The value returned by the
  9269.    OFFSET operand is an immediate (constant) operand.
  9270.  
  9271.    If the MODEL directive is used, the value returned by the OFFSET operator
  9272.    is relative to a group, whenever the data item is declared in a segment
  9273.    that is part of a group. The OFFSET operator returns the number of bytes
  9274.    between the beginning of the group and the data object. If the object is
  9275.    declared in a segment not part of a group, OFFSET returns the number of
  9276.    bytes between the beginning of the segment and the data object.
  9277.  
  9278.    If the MODEL directive is not used, OFFSET returns a value relative to the
  9279.    beginning of the segment, regardless of whether the segment is part of a
  9280.    group.
  9281.  
  9282.    If full segment definitions are given, the returned value is a memory
  9283.    operand equal to the number of bytes between the item and the beginning of
  9284.    the segment in which it is defined.
  9285.  
  9286.    The segment-override operator (:) can be used to force OFFSET to return
  9287.    the number of bytes between the item in expression and the beginning of a
  9288.    named segment or group. This is the method used to generate valid offsets
  9289.    for items in a group when full segment definitions are used. For example,
  9290.    the statement
  9291.  
  9292.                mov     bx,OFFSET DGROUP:array
  9293.  
  9294.    is not the same as
  9295.  
  9296.                mov     bx,OFFSET array
  9297.  
  9298.    if array is not in the first segment in DGROUP.
  9299.  
  9300.    Example
  9301.  
  9302.                .DATA
  9303.    string      DB      "This is it."
  9304.                .CODE
  9305.                .
  9306.                .
  9307.                .
  9308.                mov     dx,OFFSET string   ; Load offset of variable
  9309.  
  9310.  
  9311.  9.2.4.7  .TYPE Operator
  9312.  
  9313.    The .TYPE operator returns a byte that defines the mode and scope of an
  9314.    expression.
  9315.  
  9316.    Syntax
  9317.  
  9318.    .TYPE expression
  9319.  
  9320.    If expression is not valid, .TYPE returns 0. Otherwise, .TYPE returns a
  9321.    byte having the bit setting shown in Table 9.4. The .TYPE operator sets
  9322.    all bits except bit 6. Future versions of the assembler may reserve a use
  9323.    for this bit.
  9324.  
  9325.    Table 9.4 .TYPE Operator and Variable Attributes
  9326.  
  9327.    Bit Position  If Bit = 0                    If Bit = 1
  9328.    ──────────────────────────────────────────────────────────────────────────
  9329.    0             Not program related           Program related
  9330.  
  9331.    1             Not data related              Data related
  9332.  
  9333.    2             Not a constant value          Constant value
  9334.  
  9335.    3             Addressing mode is not direct Addressing mode is direct
  9336.  
  9337.    4             Not a register                Expression is a register
  9338.  
  9339.    5             Not defined                   Defined
  9340.  
  9341.    7             Local or public scope         External scope
  9342.  
  9343.    ──────────────────────────────────────────────────────────────────────────
  9344.  
  9345.  
  9346.    The .TYPE operator is typically used in macros in which different kinds of
  9347.    arguments may need to be handled differently.
  9348.  
  9349.    Example
  9350.  
  9351.    display     MACRO   string
  9352.                IF      ((.TYPE string) SHL 14) NE 8000h
  9353.                IF2
  9354.                %OUT    Argument must be a variable
  9355.                ENDIF
  9356.                ENDIF
  9357.                mov     dx,OFFSET string
  9358.                mov     ah,09h
  9359.                int     21h
  9360.                ENDM
  9361.  
  9362.    This macro checks to see if the argument passed to it is data related (a
  9363.    variable). It does this by shifting all bits except the relevant bits (1
  9364.    and 0) to the left so that they can be checked. If the data bit is not
  9365.    set, an error message is generated.
  9366.  
  9367.  
  9368.  9.2.4.8  TYPE Operator
  9369.  
  9370.    The TYPE operator returns a number that represents the type of an
  9371.    expression.
  9372.  
  9373.    Syntax
  9374.  
  9375.    TYPE expression
  9376.  
  9377.    If expression evaluates to a variable, the operator returns the number of
  9378.    bytes in each data object in the variable. Each byte in a string is
  9379.    considered a separate data object, so the TYPE operator returns 1 for
  9380.    strings.
  9381.  
  9382.    If expression evaluates to a structure or structure variable, the operator
  9383.    returns the number of bytes in the structure. If the expression is a
  9384.    label, the operator returns 0FFFFH for NEAR labels and 0FFFEH for FAR
  9385.    labels. If the expression is a constant, the operator returns 0.
  9386.  
  9387.  
  9388.  9.2.4.9  LENGTH Operator
  9389.  
  9390.    The LENGTH operator returns the number of data elements in an array or
  9391.    other variable defined with the DUP operator.
  9392.  
  9393.    Syntax
  9394.  
  9395.    LENGTH variable
  9396.  
  9397.    The returned value is the number of elements of the declared size in
  9398.    variable. If the variable was declared with nested DUP operators, only the
  9399.    value given for the outer DUP operator is returned. If the variable was
  9400.    not declared with the DUP operator, the value returned is always 1.
  9401.  
  9402.    Example
  9403.  
  9404.    array       DD      100 DUP(0FFFFFFh)
  9405.    table       DW      100 DUP(1,10 DUP(?))
  9406.    string      DB      'This is a string'
  9407.    var         DT      ?
  9408.    larray      EQU     LENGTH array       ; 100 - number of elements
  9409.    ltable      EQU     LENGTH table       ; 100 - inner DUP not counted
  9410.    lstring     EQU     LENGTH string      ; 1 - string is one element
  9411.    lvar        EQU     LENGTH var         ; 1
  9412.                .
  9413.                .
  9414.                .
  9415.                mov     cx,LENGTH array    ; Load number of elements
  9416.    again:      .                          ; Perform some operation on
  9417.                .                          ;   each element
  9418.                .
  9419.                loop    again
  9420.  
  9421.  
  9422.  9.2.4.10  SIZE Operator
  9423.  
  9424.    The SIZE operator returns the total number of bytes allocated for an array
  9425.    or other variable defined with the DUP operator.
  9426.  
  9427.    Syntax
  9428.  
  9429.    SIZE variable
  9430.  
  9431.    The returned value is equal to the value of LENGTH variable times the
  9432.    value of TYPE variable. If the variable was declared with nested DUP
  9433.    operators, only the value given for the outside DUP operator is
  9434.    considered. If the variable was not declared with the DUP operator, the
  9435.    value returned is always TYPE variable.
  9436.  
  9437.    Example
  9438.  
  9439.    array       DD      100 DUP(1)
  9440.    table       DW      100 DUP(1,10 DUP(?))
  9441.    string      DB      'This is a string'
  9442.    var         DT      ?
  9443.    sarray      EQU     SIZE array         ; 400 - elements times size
  9444.    stable      EQU     SIZE table         ; 200 - inner DUP ignored
  9445.    sstring     EQU     SIZE string        ; 1 - string is one element
  9446.    svar        EQU     SIZE var           ; 10 - bytes in variable
  9447.                .
  9448.                .
  9449.                .
  9450.                mov     cx,SIZE array      ; Load number of bytes
  9451.    again:      .                          ; Perform some operation on
  9452.                .                          ;   each byte
  9453.                .
  9454.                loop    again
  9455.  
  9456.  
  9457.  9.2.5  Operator Precedence
  9458.  
  9459.    Expressions are evaluated according to the following rules:
  9460.  
  9461.    ■  Operations of highest precedence are performed first.
  9462.  
  9463.    ■  Operations of equal precedence are performed from left to right.
  9464.  
  9465.    ■  The order of evaluation can be overridden by using parentheses.
  9466.       Operations in parentheses are always performed before any adjacent
  9467.       operations.
  9468.  
  9469.    The order of precedence for all operators is listed in Table 9.5.
  9470.    Operators on the same line have equal precedence.
  9471.  
  9472.    Table 9.5 Operator Precedence
  9473.  
  9474.    Precedence         Operators
  9475.    ──────────────────────────────────────────────────────────────────────────
  9476.    (Highest)
  9477.  
  9478.    1                  LENGTH, SIZE, WIDTH, MASK, (), [],<>
  9479.  
  9480.    2                  . (structure-field-name operator)
  9481.  
  9482.    3                  :
  9483.  
  9484.    4                  PTR, OFFSET, SEG, TYPE, THIS
  9485.  
  9486.    5                  HIGH, LOW
  9487.  
  9488.    6                  +,- (unary)
  9489.  
  9490.    7                  *,/, MOD, SHL, SHR
  9491.  
  9492.    8                  +, - (binary)
  9493.  
  9494.    9                  EQ, NE, LT, LE, GT, GE
  9495.  
  9496.    10                 NOT
  9497.  
  9498.    11                 AND
  9499.  
  9500.    12                 OR, XOR
  9501.  
  9502.    13                 SHORT, .TYPE
  9503.  
  9504.    (Lowest)
  9505.  
  9506.    ──────────────────────────────────────────────────────────────────────────
  9507.  
  9508.  
  9509.    Examples
  9510.  
  9511.    a           EQU     8 / 4 * 2          ; Equals 4
  9512.    b           EQU     8 / (4 * 2)        ; Equals 1
  9513.    c           EQU     8 + 4 * 2          ; Equals 16
  9514.    d           EQU     (8 + 4) * 2        ; Equals 24
  9515.    e           EQU     8 OR 4 AND 2       ; Equals 8
  9516.    f           EQU     (8 OR 4) AND 3     ; Equals 0
  9517.  
  9518.  
  9519.  9.3  Using the Location Counter
  9520.  
  9521.    The location counter is a special operand that, during assembly,
  9522.    represents the address of the statement currently being assembled. At
  9523.    assembly time, the location counter keeps changing, but when used in
  9524.    source code, it resolves to a constant representing an address.
  9525.  
  9526.    The location counter has the same attributes as a near label. It
  9527.    represents an offset that is relative to the current segment and is equal
  9528.    to the number of bytes generated for the segment to that point.
  9529.  
  9530.    Example 1
  9531.  
  9532.    string      DB      "Who wants to count every byte in a string, "
  9533.                DB      "especially if you might change it later."
  9534.    lstring     EQU     $-string   ; Let the assembler do it
  9535.  
  9536.    Example 1 shows one way of using the location-counter operand in
  9537.    expressions relating to data.
  9538.  
  9539.    Example 2
  9540.  
  9541.                cmp     ax,bx
  9542.                jl      shortjump  ; If ax < bx, go to "shortjump"
  9543.                .                  ;   else if ax >= bx, continue
  9544.                .
  9545.    shortjump:  .
  9546.  
  9547.                cmp     ax,bx
  9548.                jge     $+5        ; If ax >= bx, continue
  9549.                jmp     longjump   ;   else if ax < bx, go to "longjump"
  9550.                .                  ; This is "$+5"
  9551.                .
  9552.    longjump:   .
  9553.  
  9554.    Example 2 illustrates how you can use the location counter to do
  9555.    conditional jumps of more than 128 bytes. The first part shows the normal
  9556.    way of coding jumps of less than 128 bytes, and the second part shows how
  9557.    to code the same jump when the label is more than 128 bytes away.
  9558.  
  9559.  
  9560.  9.4  Using Forward References
  9561.  
  9562.    The assembler permits you to refer to labels, variable names, segment
  9563.    names, and other symbols before they are declared in the source code. Such
  9564.    references are called forward references.
  9565.  
  9566.    The assembler handles forward references by making assumptions about them
  9567.    on the first pass and then attempting to correct the assumptions, if
  9568.    necessary, on the second pass. Checking and correcting assumptions on the
  9569.    second pass takes processing time, so source code with forward references
  9570.    assembles more slowly than source code with no forward references.
  9571.  
  9572.    In addition, the assembler may make incorrect assumptions that it cannot
  9573.    correct, or corrects at a cost in program efficiency.
  9574.  
  9575.  
  9576.  9.4.1  Forward References to Labels
  9577.  
  9578.    Forward references to labels may result in incorrect or inefficient code.
  9579.  
  9580.    In the statement below, the label target is a forward reference:
  9581.  
  9582.                jmp     target             ; Generates 3 bytes in 16-bit segmen
  9583.                .
  9584.                .
  9585.                .
  9586.    target:
  9587.  
  9588.    Since the assembler processes source files sequentially, target is unknown
  9589.    when it is first encountered. It could be one of three types: short (-128
  9590.    to 127 bytes from the jump), near (-32,768 to 32,767 bytes from the jump),
  9591.    or far (in a different segment than the jump). QuickAssembler assumes that
  9592.    target is a near label, and assembles the number of bytes necessary to
  9593.    specify a near label: one byte for the instruction and two bytes for the
  9594.    operand.
  9595.  
  9596.    If, on the second pass, the assembler learns that target is a short label,
  9597.    it will need only two bytes: one for the instruction and one for the
  9598.    operand. However, it will not be able to change its previous assembly and
  9599.    the three-byte version of the assembly will stand. If the assembler learns
  9600.    that target is a far label, it will need five bytes. Since it can't make
  9601.    this adjustment, it will generate a phase error.
  9602.  
  9603.    You can override the assembler's assumptions by specifying the exact size
  9604.    of the jump. For example, if you know that a JMP instruction refers to a
  9605.    label less than 128 bytes from the jump, you can use the SHORT operator,
  9606.    as shown below:
  9607.  
  9608.                jmp     SHORT target       ; Generates 2 bytes
  9609.                .
  9610.                .
  9611.                .
  9612.    target:
  9613.  
  9614.    Using the SHORT operator makes the code smaller and slightly faster. If
  9615.    the assembler has to use the three-byte form when the two-byte form would
  9616.    be acceptable, it will generate a warning message if the warning level is
  9617.    2. (The warning level can be set with the /W option, as described in
  9618.    Appendix B, Section B.16.) You can ignore the warning, or you can go
  9619.    back to the source code and change the code to eliminate the forward
  9620.    references.
  9621.  
  9622.    ──────────────────────────────────────────────────────────────────────────
  9623.    NOTE  The SHORT operator in the example above would not be needed if
  9624.    target were located before the jump. The assembler would have already
  9625.    processed target and would be able to make adjustments based on its
  9626.    distance.
  9627.    ──────────────────────────────────────────────────────────────────────────
  9628.  
  9629.    If you use the SHORT operator when the label being jumped to is more than
  9630.    128 bytes away, QuickAssembler generates an error message. You can either
  9631.    remove the SHORT operator, or try to reorganize your program to reduce the
  9632.    distance.
  9633.  
  9634.    If a far jump to a forward-referenced label is required, you must override
  9635.    the assembler's assumptions with the FAR and PTR operators, as shown
  9636.    below:
  9637.  
  9638.                jmp     FAR PTR target     ; Generates 5 bytes
  9639.                .
  9640.                .
  9641.                .
  9642.    target:                                ; In different segment
  9643.  
  9644.    If the type of a label has been established earlier in the source code
  9645.    with an EXTRN directive, the type does not need to be specified in the
  9646.    jump statement.
  9647.  
  9648.  
  9649.  9.4.2  Forward References to Variables
  9650.  
  9651.    When QuickAssembler encounters code referencing variables that have not
  9652.    yet been defined in pass 1, it makes assumptions about the segment where
  9653.    the variable will be defined. If on pass 2 the assumptions turn out to be
  9654.    wrong, an error will occur.
  9655.  
  9656.    These problems usually occur with complex segment structures that do not
  9657.    follow the Microsoft segment conventions. The problems never appear if
  9658.    simplified segment directives are used.
  9659.  
  9660.    By default, QuickAssembler assumes that variables are referenced to the DS
  9661.    register. If a statement must access a variable in a segment not
  9662.    associated with the DS register, and if the variable has not been defined
  9663.    earlier in the source code, you must use the segment-override operator to
  9664.    specify the segment.
  9665.  
  9666.    The situation is different if neither the variable nor the segment in
  9667.    which it is defined has been defined earlier in the source code. In this
  9668.    case, you must assign the segment to a group earlier in the source code.
  9669.    QuickAssembler will then know about the existence of the segment even
  9670.    though it has not yet been defined.
  9671.  
  9672.  
  9673.  9.5  Strong Typing for Memory Operands
  9674.  
  9675.    The assembler carries out strict syntax checks for all instruction
  9676.    statements, including strong typing for operands that refer to memory
  9677.    locations. This means that when an instruction uses two operands with
  9678.    implied data types, the operand types must match. Warning messages are
  9679.    generated for nonmatching types.
  9680.  
  9681.    For example, in the following fragment, the variable string is incorrectly
  9682.    used in a move instruction:
  9683.  
  9684.                .DATA
  9685.    string      DB      "A message."
  9686.                .CODE
  9687.                .
  9688.                .
  9689.                .
  9690.                mov     ax,string[1]
  9691.  
  9692.    The ax register has WORD type, but string has BYTE type. Therefore, the
  9693.    statement generates the following warning message:
  9694.  
  9695.    Operand types must match
  9696.  
  9697.    To avoid all ambiguity and prevent the warning error, use the PTR operator
  9698.    to override the variable's type, as shown below:
  9699.  
  9700.                mov     ax,WORD PTR string[1]
  9701.  
  9702.    You can ignore the warnings if you are willing to trust the assembler's
  9703.    assumptions. When a register and memory operand are mixed, the assembler
  9704.    assumes that the register operand is always the correct size. For example,
  9705.    in the statement
  9706.  
  9707.                mov     ax,string[1]
  9708.  
  9709.    the assembler assumes that the programmer wishes the word size of the
  9710.    register to override the byte size of the variable. A word starting at
  9711.    string[1] will be moved into AX. In the statement
  9712.  
  9713.                mov     string[1],ax
  9714.  
  9715.    the assembler assumes that the programmer wishes to move the word value in
  9716.    AX into the word starting at string[1]. However, the assembler's
  9717.    assumptions are not always as clear as in these examples. You should not
  9718.    ignore warnings about type mismatches unless you are sure you understand
  9719.    how your code will be assembled.
  9720.  
  9721.    ──────────────────────────────────────────────────────────────────────────
  9722.    NOTE  Some assemblers (including early versions of the IBM Macro
  9723.    Assembler) do not do strict type checking. For compatibility with these
  9724.    assemblers, type errors are warnings rather than severe errors. Many
  9725.    assembly-language program listings in books and magazines are written for
  9726.    assemblers with weak type checking. Such programs may produce warning
  9727.    messages, but assemble correctly. You can use the /W option to turn off
  9728.    type warnings if you are sure the code is correct.
  9729.    ──────────────────────────────────────────────────────────────────────────
  9730.  
  9731.  
  9732.  
  9733.  ────────────────────────────────────────────────────────────────────────────
  9734.  Chapter 10:  Assembling Conditionally
  9735.  
  9736.  
  9737.    QuickAssembler provides two types of conditional directives,
  9738.    conditional-assembly and conditional-error directives.
  9739.    Conditional-assembly directives test for a specified condition and
  9740.    assemble a block of statements if the condition is true. Conditional-error
  9741.    directives test for a specified condition and generate an assembly error
  9742.    if the condition is true.
  9743.  
  9744.    Both kinds of conditional directives test assembly-time conditions. They
  9745.    cannot test run-time conditions. Only expressions that evaluate to
  9746.    constants during assembly can be compared or tested.
  9747.  
  9748.    Since macros and conditional-assembly directives are often used together,
  9749.    you may need to refer to Chapter 11, "Using Equates, Macros, and Repeat
  9750.    Blocks," to understand some of the examples in this chapter. In
  9751.    particular, conditional directives are frequently used with the operators
  9752.    described in Section 11.5, "Using Macro Operators."
  9753.  
  9754.  
  9755.  10.1  Using Conditional-Assembly Directives
  9756.  
  9757.    The conditional-assembly directives include the following:
  9758.  
  9759.    ELSE          IFB          IFIDN
  9760.    ENDIF         IFDEF        IFIDNI
  9761.    IF            IFDIF        IFNB
  9762.    IF1           IFDIFI       IFNDEF
  9763.    IF2           IFE
  9764.  
  9765.    The IF directives and the ENDIF and ELSE directives can be used to enclose
  9766.    the statements to be considered for conditional assembly.
  9767.  
  9768.    Syntax
  9769.  
  9770.    IFcondition
  9771.    statements
  9772.    [[ELSEIFcondition
  9773.    statements]]
  9774.    .
  9775.    .
  9776.    .
  9777.    [[ELSE
  9778.    statements]]
  9779.    ENDIF
  9780.  
  9781.    The statements following the IF directive can be any valid statements,
  9782.    including other conditional blocks. The ELSEIF and ELSE blocks are
  9783.    optional. The conditional block can contain any number of ELSEIF blocks.
  9784.    (The ELSEIF directives are listed in Section 10.1.6.) ENDIF ends the
  9785.    block.
  9786.  
  9787.    The statements following the IF directive are assembled only if the
  9788.    corresponding condition is true. If the condition is not true and an
  9789.    ELSEIF directive is used, the assembler checks to see if the corresponding
  9790.    condition is true. If so, it assembles the statements following the ELSEIF
  9791.    directive. If no IF or ELSEIF conditions are satisifed, the statements
  9792.    following the ELSE directive are assembled.
  9793.  
  9794.    IF statements can be nested up to 20 levels. A nested ELSE or ELSEIF
  9795.    directive always belongs to the nearest preceding IF statement that does
  9796.    not have its own ELSE directive.
  9797.  
  9798.  
  9799.  10.1.1  Testing Expressions with IF and IFE Directives
  9800.  
  9801.    The IF and IFE directives test the value of an expression and grant
  9802.    assembly based on the result.
  9803.  
  9804.    Syntax
  9805.  
  9806.    IF expression
  9807.    IFE expression
  9808.  
  9809.    The IF directive grants assembly if the value of expression is true
  9810.    (nonzero). The IFE directive grants assembly if the value of expression is
  9811.    false (0). The expression must evaluate to a constant value and must not
  9812.    contain forward references.
  9813.  
  9814.    Example
  9815.  
  9816.                IF      debug GT 20
  9817.                push    debug
  9818.                call    adebug
  9819.                ELSEIF  debug GT 10
  9820.                call    bdebug
  9821.                ELSE
  9822.                call    cdebug
  9823.                ENDIF
  9824.  
  9825.    In this example, a different debug routine will be called, depending on
  9826.    the value of debug.
  9827.  
  9828.  
  9829.  10.1.2  Testing the Pass with IF1 and IF2 Directives
  9830.  
  9831.    The IF1 and IF2 directives test the current assembly pass and grant
  9832.    assembly only on the pass specified by the directive. Multiple passes of
  9833.    the assembler are discussed in Appendix C, Section C.7, "Reading a Pass
  9834.    1 Listing."
  9835.  
  9836.    Syntax
  9837.  
  9838.    IF1
  9839.    IF2
  9840.  
  9841.    The IF1 directive grants assembly only on pass 1. The IF2 directive grants
  9842.    assembly only on pass 2. The directives take no arguments. If you turn on
  9843.    the One-Pass Assembly option, the IF2 directive produces an error.
  9844.  
  9845.    Macros usually only need to be processed once. You can enclose blocks of
  9846.    macros in IF1 blocks to prevent them from being reprocessed on the second
  9847.    pass.
  9848.  
  9849.    Example
  9850.  
  9851.                IF1                ; Define on first pass only
  9852.    dostuff     MACRO   argument
  9853.                .
  9854.                .
  9855.                .
  9856.                ENDM
  9857.                ENDIF
  9858.  
  9859.  
  9860.  10.1.3  Testing Symbol Definition with IFDEF and IFNDEF Directives
  9861.  
  9862.    The IFDEF and IFNDEF directives test whether a symbol has been defined and
  9863.    grant assembly based on the result.
  9864.  
  9865.    Syntax
  9866.  
  9867.    IFDEF name
  9868.    IFNDEF name
  9869.  
  9870.    The IFDEF directive grants assembly only if name is a defined label,
  9871.    variable, or symbol. The IFNDEF directive grants assembly if name has not
  9872.    yet been defined.
  9873.  
  9874.    The name can be any valid name. Note that if name is a forward reference,
  9875.    it is considered undefined on pass 1, but defined on pass 2.
  9876.  
  9877.    Example
  9878.  
  9879.                IFDEF   buffer
  9880.    buff        DB      buffer DUP(?)
  9881.                ENDIF
  9882.  
  9883.    In this example, buff is allocated only if buffer has been previously
  9884.    defined.
  9885.  
  9886.    One way to use this conditional block is to leave buffer undefined in the
  9887.    source file and define it if needed by using the /Dsymbol option (see
  9888.    Appendix B, Section B.4, "Defining Assembler Symbols") when you start
  9889.    QuickAssembler. For example, if the conditional block is in TEST.ASM, you
  9890.    could start the assembler with the following command line:
  9891.  
  9892.    QCL /Dbuffer=1024 test.asm
  9893.  
  9894.    You could also define the symbol buffer by entering buffer=1024 in the
  9895.    Defines field of the Assembler Flags dialog box.
  9896.  
  9897.    The command line would define the symbol buffer. As a result, the
  9898.    conditional-assembly block would allocate buff. However, if you didn't
  9899.    need buff, you could use the following command line:
  9900.  
  9901.    QCL test.asm
  9902.  
  9903.  
  9904.  10.1.4  Verifying Macro Parameters with IFB and IFNB Directives
  9905.  
  9906.    The IFB and IFNB directives test to see if a specified argument was passed
  9907.    to a macro and grant assembly based on the result.
  9908.  
  9909.    Syntax
  9910.  
  9911.    IFB <argument >
  9912.    IFNB <argument>
  9913.  
  9914.    These directives are always used inside macros, and they always test
  9915.    whether a real argument was passed for a specified dummy argument. The IFB
  9916.    directive grants assembly if argument is blank. The IFNB directive grants
  9917.    assembly if argument is not blank. The arguments can be any name, number,
  9918.    or expression. Angle brackets (< >) are required.
  9919.  
  9920.    Example
  9921.  
  9922.    Write       MACRO   buffer,bytes,handle
  9923.                IFNB    <handle>
  9924.                mov     bx,handle        ; (1=stdout,2=stderr,3=aux,4=printer)
  9925.                ELSE
  9926.                mov     bx,1             ; Default standard out
  9927.                ENDIF
  9928.                mov     dx,OFFSET buffer ; Address of buffer to write to
  9929.                mov     cx,bytes         ; Number of bytes to write
  9930.                mov     ah,40h
  9931.                int     21h
  9932.                ENDM
  9933.  
  9934.    In this example, a default value is used if no value is specified for the
  9935.    third macro argument.
  9936.  
  9937.  
  9938.  10.1.5  Comparing Macro Arguments with IFIDN and IFDIF Directives
  9939.  
  9940.    The IFIDN and IFDIF directives compare two macro arguments and grant
  9941.    assembly based on the result.
  9942.  
  9943.    Syntax
  9944.  
  9945.    IFIDN[[I]] <argument1>,<argument2>
  9946.    IFDIF[[I]] <argument1>,<argument2>
  9947.  
  9948.    These directives are always used inside macros, and they always test
  9949.    whether real arguments passed for two specified arguments are the same.
  9950.    The IFIDN directive grants assembly if argument1 and argument2 are
  9951.    identical. The IFDIF directive grants assembly if argument1 and argument2
  9952.    are different. The arguments can be names, numbers, or expressions. They
  9953.    must be enclosed in angle brackets and separated by a comma.
  9954.  
  9955.    The optional I at the end of the directive name specifies that the
  9956.    directive is case insensitive. Arguments that are spelled the same will be
  9957.    evaluated the same, regardless of case. If the I is not given, the
  9958.    directive is case sensitive.
  9959.  
  9960.    Example
  9961.  
  9962.    divide8     MACRO   numerator,denominator
  9963.                IFDIFI  <numerator>,<al>        ;; If numerator isn't AL
  9964.                mov     al,numerator            ;;   make it AL
  9965.                ENDIF
  9966.                xor     ah,ah
  9967.                div     denominator
  9968.                ENDM
  9969.  
  9970.    In this example, a macro uses the IFDIFI directive to check one of the
  9971.    arguments and take a different action, depending on the text of the
  9972.    string. The sample macro could be enhanced further by checking for other
  9973.    values that would require adjustment (such as a denominator passed in AL
  9974.    or passed in AH).
  9975.  
  9976.  
  9977.  10.1.6  ELSEIF Directives
  9978.  
  9979.    The assembler includes an ELSEIF conditional-assembly directive
  9980.    corresponding to each of the IF directives. The ELSEIF directives provide
  9981.    a more compact and better structured way of writing some sequences of ELSE
  9982.    and IF directives. QuickAssembler supports the following directives:
  9983.  
  9984.    ELSEIF           ELSEIFDEF           ELSEIFIDN
  9985.    ELSEIF1          ELSEIFDIF           ELSEIFIDNI
  9986.    ELSEIF2          ELSEIFDIFI          ELSEIFNB
  9987.    ELSEIFB          ELSEIFE             ELSEIFNDEF
  9988.  
  9989.    The following macro contains nested IF and ELSE blocks:
  9990.  
  9991.    ; Macro to load register for high-level-language return
  9992.    FuncRet MACRO arg,length
  9993.            LOCAL tmploc
  9994.            IF length EQ 1
  9995.               mov al,arg
  9996.            ELSE
  9997.               IF length EQ 2
  9998.                  mov ax,arg
  9999.               ELSE
  10000.                  IF length EQ 4
  10001.                     .DATA
  10002.            tmploc   DW     ?
  10003.                     DW     ?
  10004.                     .CODE
  10005.                     mov ax,WORD PTR arg
  10006.                     mov tmploc,ax
  10007.                     mov ax,WORD PTR arg+2
  10008.                     mov tmploc+2,ax
  10009.                     mov dx,SEG tmploc
  10010.                     mov ax,OFFSET tmploc
  10011.                  ELSE
  10012.                     %OUT Error in FuncRet expansion
  10013.                     .ERR
  10014.                  ENDIF
  10015.               ENDIF
  10016.            ENDIF
  10017.            ENDM
  10018.  
  10019.    The macro can be rewritten as follows, using the ELSEIF directives:
  10020.  
  10021.    FuncRet MACRO arg,length
  10022.            LOCAL tmploc
  10023.            IF length EQ 1
  10024.                     mov al,arg
  10025.            ELSEIF length EQ 2
  10026.                     mov ax,arg
  10027.            ELSEIF length EQ 4
  10028.                     .DATA
  10029.  
  10030.            tmploc   DW     ?
  10031.                     DW     ?
  10032.                     .CODE
  10033.                     mov ax,WORD PTR arg
  10034.                     mov tmploc,ax
  10035.                     mov ax,WORD PTR arg+2
  10036.                     mov tmploc+2,ax
  10037.                     mov dx,SEG tmploc
  10038.                     mov ax,OFFSET tmploc
  10039.            ELSE
  10040.                     %OUT Error in FuncRet expansion
  10041.                     .ERR
  10042.            ENDIF
  10043.            ENDM
  10044.  
  10045.  
  10046.  10.2  Using Conditional-Error Directives
  10047.  
  10048.    Conditional-error directives can be used to debug programs and check for
  10049.    assembly-time errors. By inserting a conditional-error directive at a key
  10050.    point in your code, you can test assembly-time conditions at that point.
  10051.    You can also use conditional-error directives to test for boundary
  10052.    conditions in macros.
  10053.  
  10054.    The conditional-error directives and the error messages they produce are
  10055.    listed in Table 10.1.
  10056.  
  10057.    Table 10.1 Conditional-Error Directives
  10058.  
  10059.    Directive       Number          Message
  10060.    ──────────────────────────────────────────────────────────────────────────
  10061.    .ERR1           2087            Forced error - pass1
  10062.  
  10063.    .ERR2           2088            Forced error - pass2
  10064.  
  10065.    .ERR            2089            Forced error
  10066.  
  10067.    .ERRE           2090            Forced error - expression equals 0
  10068.  
  10069.    .ERRNZ          2091            Forced error - expression not equal 0
  10070.  
  10071.    .ERRNDEF        2092            Forced error - symbol not defined
  10072.  
  10073.    .ERRDEF         2093            Forced error - symbol defined
  10074.  
  10075.    .ERRB           2094            Forced error - string blank
  10076.  
  10077.    .ERRNB          2095            Forced error - string not blank
  10078.  
  10079.    .ERRIDN [[I]]   2096            Forced error - strings identical
  10080.  
  10081.    .ERRDIF [[I]]   2097            Forced error - strings different
  10082.  
  10083.    ──────────────────────────────────────────────────────────────────────────
  10084.  
  10085.  
  10086.    Like other severe errors, those generated by conditional-error directives
  10087.    cause the assembler to return exit code 7. If a severe error is
  10088.    encountered during assembly, QuickAssembler will delete the object module.
  10089.    All conditional-error directives except ERR1 generate severe errors.
  10090.  
  10091.  
  10092.  10.2.1  Generating Unconditional Errors
  10093.          with .ERR, .ERR1, and .ERR2 Directives
  10094.  
  10095.    The .ERR, .ERR1, and .ERR2 directives force an error where the directives
  10096.    occur in the source file. The error is generated unconditionally when the
  10097.    directive is encountered, but the directives can be placed within
  10098.    conditional-assembly blocks to limit the errors to certain situations.
  10099.  
  10100.    Syntax
  10101.  
  10102.    .ERR
  10103.    .ERR1
  10104.    .ERR2
  10105.  
  10106.    The .ERR directive forces an error regardless of the pass. The .ERR1 and
  10107.    .ERR2 directives force the error only on their respective passes. The
  10108.    .ERR1 directive appears only on the screen or in the listing file if you
  10109.    use the /D option to request a pass 1 listing.
  10110.  
  10111.    You can place these directives within conditional-assembly blocks or
  10112.    macros to see which blocks are being expanded.
  10113.  
  10114.    Example
  10115.  
  10116.    IFDEF       dos
  10117.                .
  10118.                .
  10119.                .
  10120.    ELSEIFDEF   xenix
  10121.                .
  10122.                .
  10123.                .
  10124.                ELSE
  10125.                .ERR
  10126.                %OUT dos or xenix must be defined
  10127.                ENDIF
  10128.                ENDIF
  10129.  
  10130.    This example makes sure that either the symbol dos or the symbol xenix is
  10131.    defined. If neither is defined, the nested ELSE condition is assembled and
  10132.    an error message is generated. Since the .ERR directive is used, an error
  10133.    would be generated on each pass. You could use .ERR1 or .ERR2 to check if
  10134.    you want the error to be generated only on the corresponding pass.
  10135.  
  10136.  
  10137.  10.2.2  Testing Expressions with .ERRE or .ERRNZ Directives
  10138.  
  10139.    The .ERRE and .ERRNZ directives test the value of an expression and
  10140.    conditionally generate an error based on the result.
  10141.  
  10142.    Syntax
  10143.  
  10144.    .ERRE expression
  10145.    .ERRNZ expression
  10146.  
  10147.    The .ERRE directive generates an error if expression is false (0). The
  10148.    .ERRNZ directive generates an error if expression is true (nonzero). The
  10149.    expression must evaluate to a constant value and must not contain forward
  10150.    references.
  10151.  
  10152.    Example
  10153.  
  10154.    buffer      MACRO   count,bname
  10155.                .ERRE   count LE 128       ;; Allocate memory, but
  10156.    bname       DB      count DUP(0)       ;;   no more than 128 bytes
  10157.                ENDM
  10158.                .
  10159.                .
  10160.                .
  10161.                buffer  128,buf1           ; Data allocated - no error
  10162.                buffer  129,buf2           ; Error generated
  10163.  
  10164.    In this example, the .ERRE directive is used to check the boundaries of a
  10165.    parameter passed to the macro buffer. If count is less than or equal to
  10166.    128, the expression being tested by the error directive will be true
  10167.    (nonzero) and no error will be generated. If count is greater than 128,
  10168.    the expression will be false (0) and the error will be generated.
  10169.  
  10170.  
  10171.  10.2.3  Verifying Symbol Definition with .ERRDEF and .ERRNDEF Directives
  10172.  
  10173.    The .ERRDEF and .ERRNDEF directives test whether a symbol is defined and
  10174.    conditionally generate an error based on the result.
  10175.  
  10176.    Syntax
  10177.  
  10178.    .ERRDEF name
  10179.    .ERRNDEF name
  10180.  
  10181.    The .ERRDEF directive produces an error if name is defined as a label,
  10182.    variable, or symbol. The .ERRNDEF directive produces an error if name has
  10183.    not yet been defined. If name is a forward reference, it is considered
  10184.    undefined on pass 1, but defined on pass 2.
  10185.  
  10186.    Example
  10187.  
  10188.                .ERRNDEF publevel
  10189.                IF       publevel LE 2
  10190.                PUBLIC   var1, var2
  10191.                ELSE
  10192.                PUBLIC   var1, var2, var3
  10193.                ENDIF
  10194.  
  10195.    In this example, the .ERRNDEF directive at the beginning of the
  10196.    conditional block makes sure that a symbol being tested in the block
  10197.    actually exists.
  10198.  
  10199.  
  10200.  10.2.4  Testing for Macro Parameters with .ERRB and .ERRNB Directives
  10201.  
  10202.    The .ERRB and .ERRNB directives test whether a specified argument was
  10203.    passed to a macro and conditionally generate an error based on the result.
  10204.  
  10205.    Syntax
  10206.  
  10207.    .ERRB <argument>
  10208.    .ERRNB <argument>
  10209.  
  10210.    These directives are always used inside macros, and they always test
  10211.    whether a real argument was passed for a specified dummy argument. The
  10212.    .ERRB directive generates an error if argument is blank. The .ERRNB
  10213.    directive generates an error if argument is not blank. The argument can be
  10214.    any name, number, or expression. Angle brackets (<>) are required.
  10215.  
  10216.    Example
  10217.  
  10218.    work        MACRO   realarg,testarg
  10219.                .ERRB   <realarg>       ;; Error if no parameters
  10220.                .ERRNB  <testarg>       ;; Error if more than one parameter
  10221.                .
  10222.                .
  10223.                .
  10224.                ENDM
  10225.  
  10226.    In this example, error directives are used to make sure that one, and only
  10227.    one, argument is passed to the macro. The .ERRB directive generates an
  10228.    error if no argument is passed to the macro. The .ERRNB directive
  10229.    generates an error if more than one argument is passed to the macro.
  10230.  
  10231.  
  10232.  10.2.5  Comparing Macro Arguments with .ERRIDN and .ERRDIF Directives
  10233.  
  10234.    The .ERRIDN and .ERRDIF directives compare two macro arguments and
  10235.    conditionally generate an error based on the result.
  10236.  
  10237.    Syntax
  10238.  
  10239.    .ERRIDN[[I]] <argument1>,<argument2>
  10240.    .ERRDIF[[I]] <argument1>,<argument2>
  10241.  
  10242.    These directives are always used inside macros, and they always compare
  10243.    the real arguments specified for two parameters. The .ERRIDN directive
  10244.    generates an error if the arguments are identical. The .ERRDIF directive
  10245.    generates an error if the arguments are different. The arguments can be
  10246.    names, numbers, or expressions. They must be enclosed in angle brackets
  10247.    and separated by a comma.
  10248.  
  10249.    The optional I at the end of the directive name specifies that the
  10250.    directive is case insensitive. Arguments that are spelled the same will be
  10251.    evaluated the same regardless of case. If the I is not given, the
  10252.    directive is case sensitive.
  10253.  
  10254.    Example
  10255.  
  10256.    addem       MACRO    ad1,ad2,sum
  10257.                .ERRIDNI <ax>,<ad2>    ;; Error if ad2 is "ax"
  10258.                mov      ax,ad1        ;; Would overwrite if ad2 were AX
  10259.                add      ax,ad2
  10260.                mov      sum,ax        ;; Sum must be register or memory
  10261.                ENDM
  10262.  
  10263.    In this example, the .ERRIDNI directive is used to protect against passing
  10264.    the AX register as the second parameter, since this would cause the macro
  10265.    to fail.
  10266.  
  10267.  
  10268.  
  10269.  ────────────────────────────────────────────────────────────────────────────
  10270.  Chapter 11:  Using Equates, Macros, and Repeat Blocks
  10271.  
  10272.  
  10273.    This chapter explains how to use equates, macros, and repeat blocks.
  10274.    "Equates" are constant values assigned to symbols so that the symbol can
  10275.    be used in place of the value. "Macros" are a series of statements that
  10276.    are assigned a symbolic name (and, optionally, parameters) so that the
  10277.    symbol can be used in place of the statements. "Repeat blocks" are a
  10278.    special form of macro used to do repeated statements.
  10279.  
  10280.    Both equates and macros are processed at assembly time. They can simplify
  10281.    writing source code by allowing the user to substitute mnemonic names for
  10282.    constants and repetitive code. By changing a macro or equate, a programmer
  10283.    can change the effect of statements throughout the source code.
  10284.  
  10285.    In exchange for these conveniences, the programmer loses some
  10286.    assembly-time efficiency. Assembly may be slightly slower for a program
  10287.    that uses macros and equates extensively than for the same program written
  10288.    without them. However, the program without macros and equates usually
  10289.    takes longer to write and is more difficult to maintain.
  10290.  
  10291.  
  10292.  11.1  Using Equates
  10293.  
  10294.    The equate directives enable you to use symbols that represent numeric or
  10295.    string constants. QuickAssembler recognizes three kinds of equates:
  10296.  
  10297.    1. Redefinable numeric equates
  10298.  
  10299.    2. Nonredefinable numeric equates
  10300.  
  10301.    3. String equates (also called text macros)
  10302.  
  10303.  
  10304.  11.1.1  Redefinable Numeric Equates
  10305.  
  10306.    Redefinable numeric equates are used to assign a numeric constant to a
  10307.    symbol. The value of the symbol can be redefined at any point during
  10308.    assembly time. Although the value of a redefinable equate may be different
  10309.    at different points in the source code, a constant value will be assigned
  10310.    for each use, and that value will not change at run time.
  10311.  
  10312.    Redefinable equates are often used for assembly-time calculations in
  10313.    macros and repeat blocks.
  10314.  
  10315.    Syntax
  10316.  
  10317.    name=expression
  10318.  
  10319.    The equal-sign (=) directive creates or redefines a constant symbol by
  10320.    assigning the numeric value of expression to name. No storage is allocated
  10321.    for the symbol. The symbol can be used in subsequent statements as an
  10322.    immediate operand having the assigned value. It can be redefined at any
  10323.    time.
  10324.  
  10325.    The expression can be an integer, a constant expression, a one- or
  10326.    two-character string constant, or an expression that evaluates to an
  10327.    address. The name must be either a unique name or a name previously
  10328.    defined by using the equal-sign (=) directive.
  10329.  
  10330.    ──────────────────────────────────────────────────────────────────────────
  10331.    NOTE  Redefinable equates must be assigned numeric values. String
  10332.    constants longer than two characters cannot be used.
  10333.    ──────────────────────────────────────────────────────────────────────────
  10334.  
  10335.    Example
  10336.  
  10337.    counter     =       0                  ; Initialize counter
  10338.    array       LABEL   BYTE               ; Label array of increasing numbers
  10339.                REPT    100                ; Repeat 100 times
  10340.                DB      counter            ; Initialize number
  10341.    counter     =       counter + 1        ; Increment counter
  10342.                ENDM
  10343.  
  10344.    This example redefines equates inside a repeat block to declare an array
  10345.    initialized to increasing values from 0 to 100. The equal-sign directive
  10346.    is used to increment the counter symbol for each loop. See Section 11.4
  10347.    for more information on repeat blocks.
  10348.  
  10349.  
  10350.  11.1.2  Nonredefinable Numeric Equates
  10351.  
  10352.    Nonredefinable numeric equates are used to assign a numeric constant to a
  10353.    symbol. The value of the symbol cannot be redefined.
  10354.  
  10355.    Nonredefinable numeric equates are often used for assigning mnemonic names
  10356.    to constant values. This can make the code more readable and easier to
  10357.    maintain. If a constant value used in numerous places in the source code
  10358.    needs to be changed, the equate can be changed in one place rather than
  10359.    throughout the source code.
  10360.  
  10361.    Syntax
  10362.  
  10363.    name EQU expression
  10364.  
  10365.    The EQU directive creates constant symbols by assigning expression to
  10366.    name. The assembler replaces each subsequent occurrence of name with the
  10367.    value of expression. Once a numeric equate has been defined with the EQU
  10368.    directive, it cannot be redefined. Attempting to do so generates an error.
  10369.  
  10370.    ──────────────────────────────────────────────────────────────────────────
  10371.    NOTE  String constants can also be defined with the EQU directive, but the
  10372.    syntax is different, as described in Section 11.1.3, "String Equates."
  10373.    ──────────────────────────────────────────────────────────────────────────
  10374.  
  10375.    No storage is allocated for the symbol. Symbols defined with numeric
  10376.    values can be used in subsequent statements as immediate operands having
  10377.    the assigned value.
  10378.  
  10379.    Examples
  10380.  
  10381.    column      EQU     80                 ; Numeric constant 80
  10382.    row         EQU     25                 ; Numeric constant 25
  10383.    screenful   EQU     column * row       ; Numeric constant 2000
  10384.    line        EQU     row                ; Alias for "row"
  10385.  
  10386.                .DATA
  10387.    buffer      DW      screenful
  10388.  
  10389.                .CODE
  10390.                .
  10391.                .
  10392.                .
  10393.                mov     cx,column
  10394.                mov     bx,line
  10395.  
  10396.  
  10397.  11.1.3  String Equates
  10398.  
  10399.    String equates (or text macros) are used to assign a string constant to a
  10400.    symbol. String equates can be used in a variety of contexts, including
  10401.    defining aliases and string constants.
  10402.  
  10403.    Syntax
  10404.  
  10405.    name EQU{string | <string>}
  10406.  
  10407.    The EQU directive creates constant symbols by assigning string to name.
  10408.    The assembler replaces each subsequent occurrence of name with string.
  10409.    Symbols defined to represent strings with the EQU directive can be
  10410.    redefined to new strings. Symbols cannot be defined to represent strings
  10411.    with the equal-sign (=) directive.
  10412.  
  10413.    An alias is a special kind of string equate. It is a symbol that is
  10414.    equated to another symbol or keyword.
  10415.  
  10416.    If you want an equate to be a string equate, you should use angle brackets
  10417.    to force the assembler to evaluate it as a string. If you do not use angle
  10418.    brackets, the assembler will try to guess from context whether a numric or
  10419.    string equate is appropriate. This can lead to unexpected results. For
  10420.    example, the statement
  10421.  
  10422.    rt          EQU      run-time
  10423.  
  10424.    would be evaluated as run minus time, even though the user might intend to
  10425.    define the string run-time. If run and time were not already defined as
  10426.    numeric equates, the statement would generate an error. Using angle
  10427.    brackets solves this problem. The statement
  10428.  
  10429.    rt          EQU      <run-time>
  10430.  
  10431.    is evaluated as the string run-time.
  10432.  
  10433.    Examples
  10434.  
  10435.    ;String equate definitions
  10436.    pi          EQU      <3.1415>           ; String constant "3.1415"
  10437.    prompt      EQU      <'Type Name: '>    ; String constant "'Type Name: '",
  10438.    WPT         EQU      <WORD PTR>         ; String constant for "WORD PTR"
  10439.    argl        EQU      <[bp+4]>           ; String constant for "[bp+4]"
  10440.  
  10441.    ; Use of string equates
  10442.                .DATA
  10443.    message     DB       prompt             ; Allocate string "Type Name:"
  10444.    pie         DQ       pi                 ; Allocate real number 3.1415
  10445.  
  10446.                .CODE
  10447.                .
  10448.                .
  10449.                .
  10450.                inc      WPT parm1          ; Increment word value of
  10451.                                            ;   argument passed on stack
  10452.  
  10453.    Section 11.3, "Text-Macro String Directives," describes directives that
  10454.    enable you to manipulate strings. They are particularly powerful when you
  10455.    use them from within macros and repeat blocks, described later.
  10456.  
  10457.  
  10458.  11.1.4  Predefined Equates
  10459.  
  10460.    The assembler includes several predefined equates. The ones related to
  10461.    segments are described in Section 5.1.5, "Using Predefined Segment
  10462.    Equates." In addition, the following equates are available: @WordSize,
  10463.    @Cpu, and @Version.
  10464.  
  10465.    The @WordSize equate returns the size of a word for the current segment.
  10466.    With QuickAssembler, this value is always equal to 2. However, other
  10467.    versions of the assembler can assign a different value to @WordSize when
  10468.    working with 80386 extended features.
  10469.  
  10470.    ──────────────────────────────────────────────────────────────────────────
  10471.    NOTE  If you set the Preserve Case assembler flag or use the /Cl option,
  10472.    QuickAssembler considers predefined equates to be case-sensitive. The
  10473.    case-sensitive names of predefined equates are @WordSize, @Cpu, @Version,
  10474.    @CurSeg, @FileName, @CodeSize, @DataSize, @Model, @data, @data?, @fardata,
  10475.    @fardata?, and @code.
  10476.    ──────────────────────────────────────────────────────────────────────────
  10477.  
  10478.    The @Cpu equate returns a 16-bit value containing information about the
  10479.    selected processor. You select a processor by using one of the processor
  10480.    directives, such as the .286 directive. You can use the @Cpu text macro to
  10481.    control assembly of processor-specific code. Individual bits in the value
  10482.    returned by @Cpu indicate information about the selected processor.
  10483.  
  10484.    Bit                 If Bit = 1
  10485.    ──────────────────────────────────────────────────────────────────────────
  10486.    0                   8086 processor
  10487.  
  10488.    1                   80186 processor
  10489.  
  10490.    2                   80286 processor
  10491.  
  10492.    8                   8087 coprocessor instructions enabled
  10493.  
  10494.    10                  80287 coprocessor instructions enabled
  10495.  
  10496.  
  10497.    Because the processors are upwardly compatible, selecting a
  10498.    higher-numbered processor automatically sets the bits indicating
  10499.    lower-numbered processors. For example, selecting an 80286 processor
  10500.    automatically sets the 80186 and 8086 bits.
  10501.  
  10502.    Bits 4 through 6, 9, and 12 through 15 are reserved for future use and
  10503.    should be masked off when testing. Bits 3, 7, and 11 have special meaning
  10504.    to Versions 5.1 and later of the Microsoft Macro Assembler: bit 3
  10505.    indicates an 80386 processor, bit 7 indicates privilege mode enabled, and
  10506.    bit 11 indicates that 80387 coprocessor instructions are enabled.
  10507.  
  10508.    ──────────────────────────────────────────────────────────────────────────
  10509.    NOTE  The @Cpu equate only provides information about the processor
  10510.    selected during assembly by one of the processor directives. It does not
  10511.    provide information about the processor actually used when a program is
  10512.    run.
  10513.    ──────────────────────────────────────────────────────────────────────────
  10514.  
  10515.    The following example uses the @Cpu text macro to select more efficient
  10516.    instructions available only on the 80186 processor and above:
  10517.  
  10518.    ; Use the 186/286/386 pusha instruction if possible
  10519.    P186        EQU (@Cpu AND 0002h)           ; Only test 186 bit--286 and
  10520.                                               ;   386 set 186 bit as well
  10521.                .
  10522.                .
  10523.                .
  10524.  
  10525.                IF P186                         ; Non-zero if 186 processor
  10526.                   pusha                        ;   or above
  10527.                ELSE
  10528.                   push ax                      ; Do what the single
  10529.                   push cx                      ;   pusha instruction does
  10530.                   push dx
  10531.                   push bx
  10532.                   push sp
  10533.                   push bp
  10534.                   push si
  10535.                   push di
  10536.                ENDIF
  10537.  
  10538.    The @Version equate returns the version of the assembler in use. With the
  10539.    @Version equate, you can write macros that take appropriate actions for
  10540.    different versions of the assembler. Currently, the @Version equate
  10541.    returns 520 as a string of three characters.
  10542.  
  10543.    ──────────────────────────────────────────────────────────────────────────
  10544.    NOTE  Although the version number of QuickAssembler is 2.01, the @Version
  10545.    equate returns 520 rather than 201. The number 520 was selected because
  10546.    QuickAssembler is an enhancement of Version 5.1 of the Microsoft Macro
  10547.    Assembler. The @Version equate was first assembled for Version 5.1.
  10548.    ──────────────────────────────────────────────────────────────────────────
  10549.  
  10550.    You can use the IF and IFE conditional assembly directives to test for
  10551.    different versions of the assembler and to assemble different code
  10552.    depending on the version.
  10553.  
  10554.    IFNDEF       @Version
  10555.       %OUT MASM 5.0 or earlier has no extended PROC or .STARTUP
  10556.    ELSEIF       @Version EQ 510
  10557.       %OUT MASM 5.1 has extended PROC, but not .STARTUP
  10558.    ELSEIF       @Version EQ 520
  10559.       %OUT QuickAssembler 2.01 has extended PROC and .STARTUP
  10560.    ELSE
  10561.       %OUT Future assembler
  10562.    ENDIF
  10563.  
  10564.  
  10565.  11.2  Using Macros
  10566.  
  10567.    Macros enable you to assign a symbolic name to a block of source
  10568.    statements and then to use that name in your source file to represent the
  10569.    statements. Parameters can also be defined to represent arguments passed
  10570.    to the macro.
  10571.  
  10572.    Macro expansion is a text-processing function that occurs at assembly
  10573.    time. Each time QuickAssembler encounters the text associated with a macro
  10574.    name, it replaces that text with the text of the statements in the macro
  10575.    definition. Similarly, the text of parameter names is replaced with the
  10576.    text of the corresponding actual arguments.
  10577.  
  10578.    A macro can be defined any place in the source file as long as the
  10579.    definition precedes the first source line that calls the macro. Macros and
  10580.    equates are often kept in a separate file and made available to the
  10581.    program through an INCLUDE directive (see Section 11.7.1, "Using Include
  10582.    Files") at the start of the source code.
  10583.  
  10584.    Often a task can be done by using either a macro or procedure. For
  10585.    example, the addup procedure shown in Section 15.3.3, "Passing Arguments
  10586.    on the Stack," does the same thing as the addup macro in Section 11.2.1,
  10587.    "Defining Macros." Macros are expanded on every occurrence of the macro
  10588.    name, so they can increase the length of the executable file if called
  10589.    repeatedly. Procedures are coded only once in the executable file, but the
  10590.    increased overhead of saving and restoring addresses and parameters can
  10591.    make them slower.
  10592.  
  10593.    The section below tells how to define and call macros. Repeat blocks, a
  10594.    special form of macro for doing repeated operations, are discussed
  10595.    separately in Section 11.4.
  10596.  
  10597.  
  10598.  11.2.1  Defining Macros
  10599.  
  10600.    The MACRO and ENDM directives are used to define macros. MACRO designates
  10601.    the beginning of the macro block, and ENDM designates the end of the macro
  10602.    block.
  10603.  
  10604.    Syntax
  10605.  
  10606.    name MACRO [[parameter [[,parameter]]...]]
  10607.    statements
  10608.    ENDM
  10609.  
  10610.    The name must be unique and a valid symbol name. It can be used later in
  10611.    the source file to invoke the macro.
  10612.  
  10613.    The parameters (sometimes called dummy parameters) are names that act as
  10614.    placeholders for values to be passed as arguments to the macro when it is
  10615.    called. Any number of parameters can be specified, but they must all fit
  10616.    on one line. If you give more than one parameter, you must separate them
  10617.    with commas, spaces, or tabs. Commas can always be used as separators;
  10618.    spaces and tabs may cause ambiguity if the arguments are expressions.
  10619.  
  10620.    ──────────────────────────────────────────────────────────────────────────
  10621.    NOTE  This manual uses the term "parameter" to refer to a placeholder for
  10622.    a value that will be passed to a macro or procedure. Parameters appear in
  10623.    macro or procedure definitions. The term "argument" is used to refer to an
  10624.    actual value passed to the macro or procedure when it is called.
  10625.    ──────────────────────────────────────────────────────────────────────────
  10626.  
  10627.    Any valid assembler statements may be placed within a macro, including
  10628.    statements that call or define other macros. Any number of statements can
  10629.    be used. The parameters can be used any number of times in the statements.
  10630.    Macros can be nested, redefined, or used recursively, as explained in
  10631.    Section 11.6, "Using Recursive, Nested, and Redefined Macros."
  10632.  
  10633.    QuickAssembler assembles the statements in a macro only if the macro is
  10634.    called and only at the point in the source file from which it is called.
  10635.    The macro definition itself is never assembled.
  10636.  
  10637.    A macro definition can include the LOCAL directive, which lets you define
  10638.    labels used only within a macro, or the EXITM directive, which allows you
  10639.    to exit from a macro before all the statements in the block are expanded.
  10640.    These directives are discussed in Sections 11.2.3, "Using Local Symbols,"
  10641.    and 11.2.4, "Exiting from a Macro." Macro operators can also be used in
  10642.    macro definitions, as described in Section 11.5, "Using Macro Operators."
  10643.  
  10644.    Example
  10645.  
  10646.    addup       MACRO   ad1,ad2,ad3
  10647.                mov     ax,ad1      ;; First parameter in AX
  10648.                add     ax,ad2      ;; Add next two parameters
  10649.                add     ax,ad3      ;;   and leave sum in AX
  10650.                ENDM
  10651.  
  10652.    This example defines a macro named addup, which uses three parameters to
  10653.    add three values and leave their sum in the AX register. The three
  10654.    parameters will be replaced with arguments when the macro is called.
  10655.  
  10656.  
  10657.  11.2.2  Calling Macros
  10658.  
  10659.    A macro call directs QuickAssembler to copy the statements of the macro to
  10660.    the point of the call and to replace any parameters in the macro
  10661.    statements with the corresponding actual arguments.
  10662.  
  10663.    Syntax
  10664.  
  10665.    name [[argument [[,argument]]...]]
  10666.  
  10667.    The name must be the name of a macro defined earlier in the source file.
  10668.    The arguments can be any text. For example, symbols, constants, and
  10669.    registers are often given as arguments. Any number of arguments can be
  10670.    given, but they must all fit on one logical line. You can use the
  10671.    continuation character (\) to continue long macro calls on multiple
  10672.    physical lines. Multiple arguments must be separated by commas, spaces, or
  10673.    tabs.
  10674.  
  10675.    QuickAssembler replaces the first parameter with the first argument, the
  10676.    second parameter with the second argument, and so on. If a macro call has
  10677.    more arguments than the macro has parameters, the extra arguments are
  10678.    ignored. If a call has fewer arguments than the macro has parameters, any
  10679.    remaining parameters are replaced with a null (empty) string.
  10680.  
  10681.    You can use conditional statements to enable macros to check for null
  10682.    strings or other types of arguments. The macro can then take appropriate
  10683.    action to adjust to different kinds of arguments. See Chapter 10,
  10684.    "Assembling Conditionally," for more information on using
  10685.    conditional-assembly and conditional-error directives to test macro
  10686.    arguments.
  10687.  
  10688.    Example
  10689.  
  10690.    addup       MACRO   ad1,ad2,ad3        ; Macro definition
  10691.                mov     ax,ad1             ;; First parameter in AX
  10692.                add     ax,ad2             ;; Add next two parameters
  10693.                add     ax,ad3             ;;   and leave sum in AX
  10694.                ENDM
  10695.                .
  10696.                .
  10697.                .
  10698.                addup   bx,2,count         ; Macro call
  10699.  
  10700.    When the addup macro is called, QuickAssembler replaces the parameters
  10701.    with the actual parameters given in the macro call. In the example above,
  10702.    the assembler would expand the macro call to the following code:
  10703.  
  10704.                mov     ax,bx
  10705.                add     ax,2
  10706.                add     ax,count
  10707.  
  10708.    This code could be shown in an assembler listing, depending on whether the
  10709.    .LALL, .XALL, or .SALL directive was in effect (see Section 12.3,
  10710.    "Controlling the Contents of Listings").
  10711.  
  10712.  
  10713.  11.2.3  Using Local Symbols
  10714.  
  10715.    The LOCAL directive can be used within a macro to define symbols that are
  10716.    available only within the defined macro.
  10717.  
  10718.    ──────────────────────────────────────────────────────────────────────────
  10719.    NOTE  In this context, the term "local" is not related to the public
  10720.    availability of a symbol, as described in Chapter 8, "Creating Programs
  10721.    from Multiple Modules," or to variables that are defined to be local to a
  10722.    procedure, as described in Section 15.3.5, "Using Local Variables." Local
  10723.    simply means that the symbol is not known outside the macro where it is
  10724.    defined.
  10725.    ──────────────────────────────────────────────────────────────────────────
  10726.  
  10727.    Syntax
  10728.  
  10729.    LOCAL localname [[,localname]]...
  10730.  
  10731.    The localname is a temporary symbol name that is to be replaced by a
  10732.    unique symbol name when the macro is expanded. At least one local name is
  10733.    required for each LOCAL directive. If more than one local symbol is given,
  10734.    the names must be separated with commas. Once declared, local name can be
  10735.    used in any statement within the macro definition.
  10736.  
  10737.    QuickAssembler creates a new actual name for localname each time the macro
  10738.    is expanded. The actual name has the following form:
  10739.  
  10740.    ??number
  10741.  
  10742.    The number is a hexadecimal number in the range 0000 to 0FFFF. You should
  10743.    not give other symbols names in this format, since doing so may produce a
  10744.    symbol with multiple definitions. In listings, the local name is shown in
  10745.    the macro definition, but the actual name is shown in expansions of macro
  10746.    calls.
  10747.  
  10748.    Nonlocal labels may be used in a macro; but if the macro is used more than
  10749.    once, the same label will appear in both expansions, and QuickAssembler
  10750.    will display an error message, indicating that the file contains a symbol
  10751.    with multiple definitions. To avoid this problem, use only local labels
  10752.    (or redefinable equates) in macros.
  10753.  
  10754.    ──────────────────────────────────────────────────────────────────────────
  10755.    NOTE  The LOCAL directive in macro definitions must precede all other
  10756.    statements in the definition. If you try another statement (such as a
  10757.    comment directive) before the LOCAL directive, an error will be generated.
  10758.    ──────────────────────────────────────────────────────────────────────────
  10759.  
  10760.    Example
  10761.  
  10762.    power       MACRO   factor,exponent    ;; Use for unsigned only
  10763.                LOCAL   again,gotzero      ;; Declare symbols for macro
  10764.                xor     dx,dx              ;; Clear DX
  10765.                mov     cx,exponent        ;; Exponent is count for loop
  10766.                mov     ax,1               ;; Multiply by 1 first time
  10767.                jcxz    gotzero            ;; Get out if exponent is zero
  10768.                mov     bx,factor
  10769.    again:      mul     bx                 ;; Multiply until done
  10770.                loop    again
  10771.    gotzero:
  10772.                ENDM
  10773.  
  10774.    In this example, the LOCAL directive defines the local names again and
  10775.    gotzero as labels to be used within the power macro. These local names
  10776.    will be replaced with unique names each time the macro is expanded. For
  10777.    example, the first time the macro is called, again will be assigned the
  10778.    name ??0000 and gotzero will be assigned ??0001. The second time through,
  10779.    again will be assigned ??0002 and gotzero will be assigned ??0003, and so
  10780.    on.
  10781.  
  10782.  
  10783.  11.2.4  Exiting from a Macro
  10784.  
  10785.    Normally, QuickAssembler processes all the statements in a macro
  10786.    definition and then continues with the next statement after the macro
  10787.    call. However, you can use the EXITM directive to tell the assembler to
  10788.    terminate macro expansion before all the statements in the macro have been
  10789.    assembled.
  10790.  
  10791.    When the EXITM directive is encountered, the assembler exits the macro or
  10792.    repeat block immediately. Any remaining statements in the macro or repeat
  10793.    block are not processed. If EXITM is encountered in a nested macro or
  10794.    repeat block, QuickAssembler returns to expanding the outer block.
  10795.  
  10796.    The EXITM directive is typically used with conditional directives to skip
  10797.    the last statements in a macro under specified conditions. Often macros
  10798.    using the EXITM directive contain repeat blocks or are called recursively.
  10799.  
  10800.    Example
  10801.  
  10802.    allocate    MACRO   times      ; Macro definition
  10803.    x           =       0
  10804.                REPT    times      ;; Repeat up to 256 times
  10805.                IF      x GT 0FFh  ;; Is x > 255 yet?
  10806.                EXITM              ;; If so, quit
  10807.                ELSE
  10808.                DB      x          ;; Else allocate x
  10809.                ENDIF
  10810.    x           =       x + 1      ;; Increment x
  10811.                ENDM
  10812.                ENDM
  10813.  
  10814.    This example defines a macro that allocates a variable amount of data, but
  10815.    no more than 255 bytes. The macro contains an IF directive that checks the
  10816.    expression x - 0FFh. When the value of this expression is true (x-255 =
  10817.    0), the EXITM directive is processed and expansion of the macro stops.
  10818.  
  10819.  
  10820.  11.3  Text-Macro String Directives
  10821.  
  10822.    The assembler includes four text-macro string directives that let you
  10823.    manipulate literal strings or text-macro values. You use the four
  10824.    directives in much the same way you use the equal-sign (=) directive. For
  10825.    example, the following line assigns the first three characters (abc) of
  10826.    the literal string to the label three by using the SUBSTR directive:
  10827.  
  10828.    three       SUBSTR  <abcdefghijklmnopqrstuvwxyz>,1,3
  10829.  
  10830.    Each of the directives assigns its value──depending on the directive──to a
  10831.    numeric label or a text macro. The following list summarizes the four
  10832.    directives and the type of label that the directives should be used with:
  10833.  
  10834.    Directive           Description
  10835.    ──────────────────────────────────────────────────────────────────────────
  10836.    SUBSTR              Returns a substring of its text macro or literal
  10837.                        string argument. SUBSTR requires a text-macro label.
  10838.  
  10839.    CATSTR              Concatenates a variable number of strings (text macros
  10840.                        or literal strings) to form a single string. CATSTR
  10841.                        requires a text-macro label.
  10842.  
  10843.    SIZESTR             Returns the length, in characters, of its argument
  10844.                        string. SIZESTR requires a numeric label.
  10845.  
  10846.    INSTR               Returns an index indicating the starting position of a
  10847.                        substring within another string. INSTR requires a
  10848.                        numeric label.
  10849.  
  10850.  
  10851.    Strings used as arguments in the directives must be text enclosed in angle
  10852.    brackets (< >), previously defined text macros, or expressions starting
  10853.    with a percent sign (%). Numeric arguments can be numeric constants or
  10854.    expressions that evaluate to constants during assembly.
  10855.  
  10856.    The next four sections describe the directives in more detail.
  10857.  
  10858.  
  10859.  11.3.1  The SUBSTR Directive
  10860.  
  10861.    The SUBSTR directive returns a substring from a given string.
  10862.  
  10863.    Syntax
  10864.  
  10865.    textlabel SUBSTR string,start[[, length]]
  10866.  
  10867.    The SUBSTR directive takes the following arguments:
  10868.  
  10869.    Argument            Description
  10870.    ──────────────────────────────────────────────────────────────────────────
  10871.    textlabel           The text label the result is assigned to.
  10872.  
  10873.    string              The string the substring is extracted from.
  10874.  
  10875.    start               The starting position of the substring. The first
  10876.                        character in the string has a position of one.
  10877.  
  10878.    length              The number of characters to extract. If omitted,
  10879.                        SUBSTR returns all characters to the right of position
  10880.                        start, including the character at position start.
  10881.  
  10882.  
  10883.    In the following lines, the text macro freg is assigned the first two
  10884.    characters of the text macro reglist:
  10885.  
  10886.    reglist     EQU     <ax,bx,cx,dx>
  10887.                .
  10888.                .
  10889.                .
  10890.    freg        SUBSTR  reglist,1,2   ; freg = ax
  10891.  
  10892.  
  10893.  11.3.2  The CATSTR Directive
  10894.  
  10895.    The CATSTR directive concatenates a series of strings.
  10896.  
  10897.    Syntax
  10898.  
  10899.    textlabel CATSTR string[[, string]]...
  10900.  
  10901.    The CATSTR directive takes the following arguments:
  10902.  
  10903.    Argument            Description
  10904.    ──────────────────────────────────────────────────────────────────────────
  10905.    textlabel           The text label the result is assigned to
  10906.  
  10907.    string              The string or strings concatenated and assigned to
  10908.                        textlabel
  10909.  
  10910.  
  10911.    The following lines concatenate the two literal strings and assign the
  10912.    result to the text macro lstring:
  10913.  
  10914.    lstring     CATSTR   <a b c>, <d e f>,       ; lstring = a b c d e f
  10915.  
  10916.  
  10917.  11.3.3  The SIZESTR Directive
  10918.  
  10919.    The SIZESTR directive assigns the length of its argument string to a
  10920.    numeric label.
  10921.  
  10922.    Syntax
  10923.  
  10924.    numericlabel SIZESTR string
  10925.  
  10926.    The SIZESTR directive takes the following arguments:
  10927.  
  10928.    Argument            Description
  10929.    ──────────────────────────────────────────────────────────────────────────
  10930.    numericlabel        The numeric label that the assembler assigns the
  10931.                        string length to
  10932.  
  10933.    string              The string whose length is returned
  10934.  
  10935.  
  10936.    The following lines set slength to 8──the length of the text macro
  10937.    tstring:
  10938.  
  10939.    tstring     EQU      <ax bx cx>
  10940.                .
  10941.                .
  10942.                .
  10943.    slength     SIZESTR  tstring                 ; slength = 8
  10944.  
  10945.    A null string has a length of zero.
  10946.  
  10947.  
  10948.  11.3.4  The INSTR Directive
  10949.  
  10950.    The INSTR directive returns the position of a string within another
  10951.    string. The directive returns 0 if the string is not found. The first
  10952.    character in a string has a position of one.
  10953.  
  10954.    Syntax
  10955.  
  10956.    numericlabel INSTR [[start,]]string1, string2
  10957.  
  10958.    The INSTR directive takes the following arguments:
  10959.  
  10960.    Argument            Description
  10961.    ──────────────────────────────────────────────────────────────────────────
  10962.    numbericlabel       The numeric label the substring's position is assigned
  10963.                        to.
  10964.  
  10965.    start               The starting position for the search. When omitted,
  10966.                        the INSTR directive starts searching at the first
  10967.                        character. The first character in the string has a
  10968.                        position of one.
  10969.  
  10970.    string1             The string being searched.
  10971.  
  10972.    string2             The string to look for.
  10973.  
  10974.  
  10975.    The following lines set colpos to the character position of the first
  10976.    colon in segarg:
  10977.  
  10978.    segarg      EQU    <ES:AX>
  10979.                .
  10980.                .
  10981.                .
  10982.    colpos      INSTR  segarg,<:> ; colpos = 3
  10983.  
  10984.  
  10985.  11.3.5  Using String Directives Inside Macros
  10986.  
  10987.    The following example uses the text-macro string directives CATSTR, INSTR,
  10988.    SIZESTR, and SUBSTR. It defines two macros, SaveRegs and RestRegs, that
  10989.    save and restore registers on the stack. The macros are written so that
  10990.    RestRegs restores only the most recently saved group of registers.
  10991.  
  10992.    The SaveRegs macro uses a text macro, regpushed, to keep track of the
  10993.    registers pushed onto the stack. The RestRegs macro uses this string to
  10994.    restore the proper registers. Each time the SaveRegs macro is invoked, it
  10995.    adds a pound sign (#) to the string to mark the start of a new group of
  10996.    registers. The RestRegs macro restores the most recently saved group by
  10997.    finding the first pound sign in the string, creating a substring
  10998.    containing the saved register names, and then looping and generating PUSH
  10999.    instructions.
  11000.  
  11001.    ; Initialize regpushed to the null string
  11002.    regpushed       EQU     <>
  11003.  
  11004.    ; SaveRegs
  11005.    ; Loops and generates a push for each argument register.
  11006.    ; Saves each register name in regpushed.
  11007.  
  11008.    SaveRegs        MACRO   r1,r2,r3,r4,r5,r6,r7,r8,r9
  11009.       regpushed    CATSTR  <#>,regpushed   ;; Mark a new group of regs
  11010.                    IRP reg,<r1,r2,r3,r4,r5,r6,r7,r8,r9>
  11011.                       IFNB <reg>
  11012.                          push reg          ;; Push and record a register
  11013.       regpushed          CATSTR    <reg>,<,>,regpushed
  11014.                       ELSE
  11015.                          EXITM             ;; Quit on blank argument
  11016.                       ENDIF
  11017.                    ENDM
  11018.                    ENDM
  11019.  
  11020.    ; RestRegs
  11021.    ; Generates a pop for each register in the most recently saved groups
  11022.  
  11023.    RestRegs        MACRO
  11024.       numloc       INSTR  regpushed,<#>    ;; Find location of #
  11025.       reglist      SUBSTR regpushed,1,numloc-1 ;; Get list of registers to pop
  11026.        reglen       SIZESTR regpushed       ;; Adjust numloc if # is notlast
  11027.                     IF reglen GT numloc     ;; item in the string
  11028.                       numloc = numloc + 1
  11029.                    ENDIF
  11030.       regpushed    SUBSTR regpushed,numloc ;; Remove list from regpushed
  11031.       %            IRP reg,<reglist>       ;; Generate pop for each register
  11032.                    IFNB <reg>
  11033.                       pop reg
  11034.                    ENDIF
  11035.                    ENDM
  11036.                    ENDM
  11037.  
  11038.    The following lines from a listing file show the sample code that the
  11039.    macros would generate (a 2 marks lines generated by the macros):
  11040.  
  11041.    SaveRegs      ax,bx
  11042.    2                     push ax           ;
  11043.    2                     push bx           ;
  11044.      SaveRegs      cx
  11045.    2                     push cx           ;
  11046.      SaveRegs      dx
  11047.    2                     push dx           ;
  11048.      RestRegs
  11049.    2                     pop dx
  11050.      RestRegs
  11051.    2                     pop cx
  11052.      RestRegs
  11053.    2                     pop bx
  11054.    2                     pop ax
  11055.  
  11056.  
  11057.  11.4  Defining Repeat Blocks
  11058.  
  11059.    Repeat blocks are a special form of macro that allows you to create blocks
  11060.    of repeated statements. They differ from macros in that they are not
  11061.    named, and thus cannot be called. However, like macros, they can have
  11062.    parameters that are replaced by actual arguments during assembly. Macro
  11063.    operators, symbols declared with the LOCAL directive, and the EXITM
  11064.    directive can be used in repeat blocks. Like macros, repeat blocks are
  11065.    always terminated by an ENDM directive.
  11066.  
  11067.    Repeat blocks are frequently placed in macros in order to repeat some of
  11068.    the statements in the macro. They can also be used independently, usually
  11069.    for declaring arrays with repeated data elements.
  11070.  
  11071.    Repeat blocks are processed at assembly time and should not be confused
  11072.    with the REP instruction, which causes string instructions to be repeated
  11073.    at run time, as explained in Chapter 16, "Processing Strings."
  11074.  
  11075.    Three different kinds of repeat blocks can be defined by using the REPT,
  11076.    IRP, and IRPC directives. The difference between them is in how the number
  11077.    of repetitions is specified.
  11078.  
  11079.  
  11080.  11.4.1  The REPT Directive
  11081.  
  11082.    The REPT directive is used to create repeat blocks in which the number of
  11083.    repetitions is specified with a numeric argument.
  11084.  
  11085.    Syntax
  11086.  
  11087.    REPT   expression
  11088.    statements
  11089.    ENDM
  11090.  
  11091.    The expression must evaluate to a numeric constant (a 16-bit unsigned
  11092.    number). It specifies the number of repetitions. Any valid assembler
  11093.    statements may be placed within the repeat block.
  11094.  
  11095.    Example
  11096.  
  11097.    alphabet    LABEL   BYTE
  11098.    x           =       0          ;; Initialize
  11099.                REPT    26         ;; Specify 26 repetitions
  11100.                DB      'A' + x    ;; Allocate ASCII code for letter
  11101.    x           =       x + 1      ;; Increment
  11102.                ENDM
  11103.  
  11104.    This example repeats the equal-sign (=) and DB directives to initialize
  11105.    ASCII values for each uppercase letter of the alphabet.
  11106.  
  11107.  
  11108.  11.4.2  The IRP Directive
  11109.  
  11110.    The IRP directive is used to create repeat blocks in which the number of
  11111.    repetitions, as well as parameters for each repetition, is specified in a
  11112.    list of arguments.
  11113.  
  11114.    Syntax
  11115.  
  11116.    IRP parameter,<argument[[,argument]]...>
  11117.    statements
  11118.    ENDM
  11119.  
  11120.    The assembler statements inside the block are repeated once for each
  11121.    argument in the list enclosed by angle brackets (< >). The parameter is a
  11122.    name for a placeholder to be replaced by the current argument. Each
  11123.    argument can be text, such as a symbol, string, or numeric constant. Any
  11124.    number of arguments can be given. If multiple arguments are given, they
  11125.    must be separated by commas. The angle brackets (< >) around the argument
  11126.    list are required. The parameter can be used any number of times in the
  11127.    statements.
  11128.  
  11129.    When QuickAssembler encounters an IRP directive, it makes one copy of the
  11130.    statements for each argument in the enclosed list. While copying the
  11131.    statements, it substitutes the current argument for all occurrences of
  11132.    parameter in these statements. If a null argument (< >) is found in the
  11133.    list, the dummy name is replaced with a blank value. If the argument list
  11134.    is empty, the IRP directive is ignored and no statements are copied.
  11135.  
  11136.    Example
  11137.  
  11138.    numbers     LABEL   BYTE
  11139.                IRP     x,<0,1,2,3,4,5,6,7,8,9>
  11140.                DB      10 DUP(x)
  11141.                ENDM
  11142.  
  11143.    This example repeats the DB directive 10 times, allocating 10 bytes for
  11144.    each number in the list. The resulting statements create 100 bytes of
  11145.    data, starting with 10 zeros, followed by 10 ones, and so on.
  11146.  
  11147.  
  11148.  11.4.3  The IRPC Directive
  11149.  
  11150.    The IRPC directive is used to create repeat blocks in which the number of
  11151.    repetitions, as well as arguments for each repetition, is specified in a
  11152.    string.
  11153.  
  11154.    Syntax
  11155.  
  11156.    IRPC parameter,string
  11157.    statements
  11158.    ENDM
  11159.  
  11160.    The assembler statements inside the block are repeated as many times as
  11161.    there are characters in string. The parameter is a name for a placeholder
  11162.    to be replaced by the current character in the string. The string can be
  11163.    any combination of letters, digits, and other characters. It should be
  11164.    enclosed with angle brackets (< >) if it contains spaces, commas, or other
  11165.    separating characters. The parameter can be used any number of times in
  11166.    these statements.
  11167.  
  11168.    When QuickAssembler encounters an IRPC directive, it makes one copy of the
  11169.    statements for each character in the string. While copying the statements,
  11170.    it substitutes the current character for all occurrences of parameter in
  11171.    these statements.
  11172.  
  11173.    Example 1
  11174.  
  11175.    ten         LABEL   BYTE
  11176.                IRPC    x,0123456789
  11177.                DB      x
  11178.                ENDM
  11179.  
  11180.    Example 1 repeats the DB directive 10 times, once for each character in
  11181.    the string 0123456789. The resulting statements create 10 bytes of data
  11182.    having the values 0-9.
  11183.  
  11184.    Example 2
  11185.  
  11186.                IRPC    letter,ABCDEFGHIJKLMNOPQRSTUVWXYZ
  11187.                DB      '&letter'          ; Allocate uppercase letter
  11188.                DB      '&letter'+20h      ; Allocate lowercase letter
  11189.                DB      '&letter'-40h      ; Allocate number of letter
  11190.                ENDM
  11191.  
  11192.    Example 2 allocates the ASCII codes for uppercase, lowercase, and numeric
  11193.    versions of each letter in the string. Notice that the substitute operator
  11194.    (&) is required so that letter will be treated as an argument rather than
  11195.    a string. See Section 11.5.1, "Substitute Operator," for more
  11196.    information.
  11197.  
  11198.  
  11199.  11.5  Using Macro Operators
  11200.  
  11201.    Macro and conditional directives use the following special set of macro
  11202.    operators:
  11203.  
  11204.    Operator            Definition
  11205.    ──────────────────────────────────────────────────────────────────────────
  11206.    &                   Substitute operator
  11207.  
  11208.    <>                  Literal-text operator
  11209.  
  11210.    !                   Literal-character operator
  11211.  
  11212.    %                   Expression operator
  11213.  
  11214.    ;;                  Macro comment
  11215.  
  11216.  
  11217.    When used in a macro definition, a macro call, a repeat block, or as the
  11218.    argument of a conditional-assembly directive, these operators carry out
  11219.    special control operations, such as text substitution.
  11220.  
  11221.  
  11222.  11.5.1  Substitute Operator
  11223.  
  11224.    The substitute operator (&) enables substitution of macro parameters to
  11225.    take place, even when the parameter occurs within a larger word or within
  11226.    a quoted string.
  11227.  
  11228.    Syntax
  11229.  
  11230.    You can use the substitute operator in any one of three different ways:
  11231.  
  11232.    name1&name2
  11233.    name&
  11234.    &name
  11235.  
  11236.    The assembler responds by analyzing name1 and name2 separately, then
  11237.    joining them together. If either name1 or name2 is a parameter, the
  11238.    assembler replaces each parameter by an actual argument before joining the
  11239.    names. You can join any number of names with the substitute operator, so
  11240.    that items such as a&b&c are valid.
  11241.  
  11242.    The last two forms are useful when a parameter name appears within a
  11243.    quoted string. The assembler responds by substituting the actual argument
  11244.    for the parameter; when not next to an ampersand (&), the assembler
  11245.    considers the parameter name just part of the string data.
  11246.  
  11247.    Example
  11248.  
  11249.    declare     MACRO   x,y
  11250.    xy          DW      0
  11251.    x&y         DW      0
  11252.    x&str       DB      'x and y params are &x and &y'
  11253.                ENDM
  11254.  
  11255.    The example above demonstrates how the presence or absence of the
  11256.    substitute operator affects macro substitution. Given the macro definition
  11257.    above, the statement
  11258.  
  11259.                declare foot,ball
  11260.  
  11261.    is expanded to
  11262.  
  11263.    xy          DW
  11264.    football    DW      0
  11265.    footstr     DB      'x and y params are foot and ball'
  11266.  
  11267.    In the first statement of the macro, xy is not identified with either of
  11268.    the parameters x or y; instead, xy forms a distinct name. No substitution
  11269.    takes place. In the second statement, the assembler interprets x&y by
  11270.    analyzing x and y as separate names, performing the appropriate parameter
  11271.    substitution in each case, and then joining the resulting names together.
  11272.  
  11273.    When you use the substitute operator with nested macros and repeat blocks,
  11274.    the assembler applies the following rules to expressions outside of
  11275.    quotes:
  11276.  
  11277.    1. Perform parameter substitution as described above.
  11278.  
  11279.    2. Remove exactly one of the substitute operators (&) from the group. The
  11280.       assembler strips off an operator whether or not a parameter was
  11281.       substituted.
  11282.  
  11283.    The number of ampersands (&) you use should never be greater than the
  11284.    number of levels of nesting. If you use too few ampersands, proper
  11285.    substitution will not take place. If you use too many ampersands, text
  11286.    such as x&y will remain after macro expansion is complete. Such
  11287.    expressions are invalid.
  11288.  
  11289.    When an ampersand appears inside quotes, the assembler removes ampersands
  11290.    on either side of a macro parameter when substitution is possible. When
  11291.    substitution is not possible (because the parameter name is not defined at
  11292.    the current level of nesting), the assembler leaves the ampersand as it
  11293.    is. With this method, parameter substitution automatically takes place at
  11294.    the appropriate level of nesting.
  11295.  
  11296.  
  11297.  11.5.2  Literal-Text Operator
  11298.  
  11299.    The literal-text operator (< >) directs QuickAssembler to treat a list as
  11300.    a single string rather than as separate arguments.
  11301.  
  11302.    Syntax
  11303.  
  11304.    <text >
  11305.  
  11306.    The text is considered a single literal element even if it contains
  11307.    commas, spaces, or tabs. The literal-text operator is most often used in
  11308.    macro calls and with the IRP directive to ensure that values in a
  11309.    parameter list are treated as a single parameter.
  11310.  
  11311.    The literal-text operator can also be used to force QuickAssembler to
  11312.    treat special characters, such as the semicolon or the ampersand,
  11313.    literally. For example, the semicolon inside angle brackets <;> becomes a
  11314.    semicolon, not a comment indicator.
  11315.  
  11316.    QuickAssembler removes one set of angle brackets each time the parameter
  11317.    is used in a macro. When using nested macros, you will need to supply as
  11318.    many sets of angle brackets as there are levels of nesting.
  11319.  
  11320.    Example
  11321.  
  11322.                work    1,2,3,4,5          ; Passes five parameters to "work"
  11323.  
  11324.                work    <1,2,3,4,5>        ; Passes one five-element
  11325.                                           ;   parameter to "work"
  11326.  
  11327.    When the IRP directive is used inside a macro definition and when the
  11328.    argument list of the IRP directive is also a parameter of the macro, you
  11329.    must use the literal-text operator (< >) to enclose the macro parameter.
  11330.  
  11331.    For example, in the following macro definition, the parameter x is used as
  11332.    the argument list for the IRP directive:
  11333.  
  11334.    init        MACRO   x
  11335.                IRP     y,<x>
  11336.                DB      y
  11337.                ENDM
  11338.                ENDM
  11339.  
  11340.    If this macro is called with
  11341.  
  11342.                init    <0,1,2,3,4,5,6,7,8,9>
  11343.  
  11344.    the macro removes the angle brackets from the parameter so that it is
  11345.    expanded as 0,1,2,3,4,5,6,7,8,9. The brackets inside the repeat block are
  11346.    necessary to put the angle brackets back on. The repeat block is then
  11347.    expanded as shown below:
  11348.  
  11349.                IRP     y,<0,1,2,3,4,5,6,7,8,9>
  11350.                DB      y
  11351.                ENDM
  11352.  
  11353.  
  11354.  11.5.3  Literal-Character Operator
  11355.  
  11356.    The literal-character operator (!) forces the assembler to treat a
  11357.    specified character literally rather than as a symbol.
  11358.  
  11359.    Syntax
  11360.  
  11361.    !character
  11362.  
  11363.    The literal-character operator is used with special characters, such as
  11364.    the semicolon or ampersand, when meaning of the special character must be
  11365.    suppressed. Using the literal-character operator is the same as enclosing
  11366.    a single character in brackets. For example, !! is the same as <!>.
  11367.  
  11368.    Example
  11369.  
  11370.    errgen      MACRO   y,x
  11371.                PUBLIC  err&y
  11372.    err&y       DB      'Error &y: &x'
  11373.                ENDMW
  11374.  
  11375.                .
  11376.                .
  11377.                .
  11378.                errgen  103,<Expression !> 255>
  11379.  
  11380.    The example macro call is expanded to allocate the string Error 103:
  11381.    Expression > 255. Without the literal-character operator, the greater-than
  11382.    symbol would be interpreted as the end of the argument and an error would
  11383.    result.
  11384.  
  11385.  
  11386.  11.5.4  Expression Operator
  11387.  
  11388.    The expression operator (%) causes the assembler to treat the argument
  11389.    following the operator as an expression.
  11390.  
  11391.    Syntax
  11392.  
  11393.    %text
  11394.  
  11395.    QuickAssembler computes the expression's value and replaces text with the
  11396.    result. The expression can be either a numeric expression or a text
  11397.    equate. Additional arguments after an argument that uses the expression
  11398.    operator must be preceded by a comma, not a space or tab.
  11399.  
  11400.    The expression operator is typically used in macro calls when the
  11401.    programmer needs to pass the result of an expression rather than the
  11402.    actual expression to a macro.
  11403.  
  11404.    Example
  11405.  
  11406.    printe      MACRO   exp,val
  11407.                IF1                        ;; On pass 1 only
  11408.                %OUT    exp = val          ;; Display expression and result
  11409.                ENDIF                      ;;   to screen
  11410.                ENDM
  11411.  
  11412.    sym1        EQU     100
  11413.    sym2        EQU     200
  11414.    msg         EQU     <"Hello, World.">
  11415.  
  11416.                printe  <sym1 + sym2>,%(sym1 + sym2)
  11417.                printe  msg,%msg
  11418.  
  11419.    In the first macro call, the text literal sym1 + sym2 = is passed to the
  11420.    parameter exp, and the result of the expression is passed to the parameter
  11421.    val. In the second macro call, the equate name msg is passed to the
  11422.    parameter exp, and the text of the equate is passed to the parameter val.
  11423.    As a result, Quick-Assembler displays the following messages:
  11424.  
  11425.    sym1 + sym2 = 300
  11426.    msg = "Hello, World."
  11427.  
  11428.    The %OUT directive, which sends a message to the screen, is described in
  11429.    Section 12.1, "Sending Messages to the Standard Output Device"; the IF1
  11430.    directive is described in Section 10.1.2, "Testing the Pass with IF1 and
  11431.    IF2 Directives."
  11432.  
  11433.    You can also use the expression operator (%) to substitute the values of
  11434.    text macros for the macro names anywhere a text-macro name appears. When
  11435.    the expression operator is the first item on a line and is followed by one
  11436.    or more blanks or tabs, the line is scanned for text macros and the values
  11437.    of the macros are substituted. Using the expression operator, you can
  11438.    force substitution of text macros wherever they appear in a line. The
  11439.    assembler re-scans the line until all substitutions have been made.
  11440.  
  11441.    ──────────────────────────────────────────────────────────────────────────
  11442.    NOTE  Text macros are always evaluated when they appear in the name or
  11443.    operation fields. The expression operator is required to evaluate a text
  11444.    macro only when the macro appears in the operand field.
  11445.    ──────────────────────────────────────────────────────────────────────────
  11446.  
  11447.    This use of the expression operator eliminates the need to do a macro call
  11448.    in order to evaluate a text macro. For example, the following macro uses a
  11449.    separate macro, popregs, to evaluate the text macro regpushed:
  11450.  
  11451.    regpushed   EQU     <ax,bx,cx>
  11452.                .
  11453.                .
  11454.                .
  11455.    RestRegs    MACRO
  11456.                popregs %regpushed
  11457.                ENDM
  11458.  
  11459.    popregs     MACRO   reglist
  11460.                IRP     reg,<reglist>
  11461.                   pop  reg
  11462.                ENDM
  11463.                ENDM
  11464.  
  11465.    The use of the expression operator to evaluate text macros in a line makes
  11466.    the popregs macro unnecessary:
  11467.  
  11468.    regpushed   EQU     <ax,bx,cx>
  11469.                .
  11470.                .
  11471.                .
  11472.    RestRegs    MACRO
  11473.      %         IRP     reg,<regpushed>   ;; % operator makes
  11474.                                          ;;   separate macro unnecessary
  11475.                   pop  reg
  11476.                ENDM
  11477.                ENDM
  11478.  
  11479.    You cannot use the EQU directive to assign a value to a text macro in a
  11480.    line evaluated with the expression operator. For example, the following
  11481.    lines generate an error:
  11482.  
  11483.    strpos      EQU  <[si]+12>
  11484.    .
  11485.    .
  11486.    .
  11487.    % wpstrpos  EQU  <WORD PTR strpos>
  11488.  
  11489.    On pass 1, wpstrpos is defined as a text macro that is expanded on pass 2.
  11490.    Thus, on pass 2 the second EQU directive becomes
  11491.  
  11492.    WORD PTR [si]+12     EQU  <WORD PTR [si]+12>
  11493.  
  11494.    and generates an error.
  11495.  
  11496.    Instead, use the CATSTR directive to assign values to text macros (see
  11497.    Section 11.3, "Text-Macro String Directives," for more information about
  11498.    CATSTR and other text-macro string directives). The previous example
  11499.    should be rewritten as follows:
  11500.  
  11501.    strpos      EQU  <[si]+12>
  11502.    .
  11503.    .
  11504.    .
  11505.    wpstrpos    CATSTR  <WORD PTR >, strpos
  11506.  
  11507.    If the text macro evaluates to a valid name, there is no error when you
  11508.    use EQU. The following lines do not generate an error, but define two
  11509.    names, one (numlabel) with the value 5, the other (tmacro) with the value
  11510.    <numlabel>:
  11511.  
  11512.    tmacro      EQU  <numlabel>
  11513.    % tmacro    EQU  5
  11514.  
  11515.    You can also use the substitution operator (&) with text macros just as
  11516.    you would inside a macro:
  11517.  
  11518.    SegName          EQU   <MySeg>
  11519.    .
  11520.    .
  11521.    .
  11522.    % SegName&_text  SEGMENT PUBLIC 'CODE'
  11523.  
  11524.    The final line, after expanding the text macro, becomes:
  11525.  
  11526.    MySeg_text       SEGMENT PUBLIC 'CODE'
  11527.  
  11528.    The substitution operator separates the text-macro name from the text that
  11529.    immediately follows it. The name appears to the assembler as segName_text
  11530.    without the substitution operator, and the assembler fails to recognize
  11531.    the text macro.
  11532.  
  11533.  
  11534.  11.5.5  Macro Comments
  11535.  
  11536.    A macro comment is any text in a macro definition that does not need to be
  11537.    copied in the macro expansion. A double semicolon (;;) is used to start a
  11538.    macro comment.
  11539.  
  11540.    Syntax
  11541.  
  11542.    ;;text
  11543.  
  11544.    All text following the double semicolon (;;) is ignored by the assembler
  11545.    and will appear only in the macro definition when the source listing is
  11546.    created.
  11547.  
  11548.    The regular comment operator (;) can also be used in macros. However,
  11549.    regular comments may appear in listings when the macro is expanded. Macro
  11550.    comments will appear in the macro definition, but not in macro expansions.
  11551.    Whether or not regular comments are listed in macro expansions depends on
  11552.    the use of the .LALL, .XALL, and .SALL directives, as described in Section
  11553.    12.2.3, "Controlling Page Breaks."
  11554.  
  11555.  
  11556.  11.6  Using Recursive, Nested, and Redefined Macros
  11557.  
  11558.    The concept of replacing macro names with predefined macro text is simple,
  11559.    but in practice it has many implications and potentially unexpected side
  11560.    effects. The following sections discuss advanced macro features (such as
  11561.    nesting, recursion, and redefinition) and point out some side effects of
  11562.    macros.
  11563.  
  11564.  
  11565.  11.6.1  Using Recursion
  11566.  
  11567.    Macro definitions can be recursive: that is, they can call themselves.
  11568.    Using recursive macros is one way of doing repeated operations. The macro
  11569.    does a task, and then calls itself to do the task again. The recursion is
  11570.    repeated until a specified condition is met.
  11571.  
  11572.    Example
  11573.  
  11574.    pushall     MACRO   reg1,reg2,reg3,reg4,reg5,reg6
  11575.                IFNB    <reg1>         ;; If parameter not blank
  11576.                push    reg1           ;;   push one register and repeat
  11577.                pushall reg2,reg3,reg4,reg5,reg6
  11578.                ENDIF
  11579.                ENDM
  11580.                .
  11581.                .
  11582.                .
  11583.    pushall     ax,bx,si,ds
  11584.    pushall     cs,es
  11585.  
  11586.    In this example, the pushall macro repeatedly calls itself to push a
  11587.    register given in a parameter until no parameters are left to push. A
  11588.    variable number of parameters (up to six) can be given.
  11589.  
  11590.  
  11591.  11.6.2  Nesting Macro Definitions
  11592.  
  11593.    One macro can define another. QuickAssembler does not process nested
  11594.    definitions until the outer macro has been called. Therefore, nested
  11595.    macros cannot be called until the outer macro has been called at least
  11596.    once. Macro definitions can be nested to any depth. Nesting is limited
  11597.    only by the amount of memory available when the source file is assembled.
  11598.    Using a macro to create similar macros can make maintenance easier. If you
  11599.    want to change all the macros, change the outer macro and it automatically
  11600.    changes the others.
  11601.  
  11602.    Example
  11603.  
  11604.    shifts      MACRO   opname             ; Define macro that defines macros
  11605.    opname&s    MACRO   operand,rotates
  11606.                IF      rotates LE 4
  11607.                REPT    rotates
  11608.                opname  operand,1          ;; One at a time is faster
  11609.                ENDM                       ;;   for 4 or less on 8088/8086
  11610.                ELSE
  11611.                mov     cl,rotates         ;; Using CL is faster
  11612.                opname  operand,cl         ;;   for more than 4 on 8088/8086
  11613.                ENDIF
  11614.                ENDM
  11615.                ENDM
  11616.  
  11617.                shifts  ror                ; Call macro to new macros
  11618.                shifts  rol
  11619.                shifts  shr
  11620.                shifts  shl
  11621.                shifts  rcl
  11622.                shifts  rcr
  11623.                shifts  sal
  11624.                shifts  sar
  11625.                .
  11626.                .
  11627.                .
  11628.                shrs    ax,5               ; Call defined macros
  11629.                rols    bx,3
  11630.  
  11631.    This macro, when called as shown, creates macros for multiple shifts with
  11632.    each of the shift and rotate instructions. All the macro names are
  11633.    identical except for the instruction. For example, the macro for the SHR
  11634.    instruction is called shrs; the macro for the ROL instruction is called
  11635.    rols. If you want to enhance the macros by doing more parameter checking,
  11636.    you can modify the original macro. Doing so will change the created macros
  11637.    automatically. This macro uses the substitute operator, as described in
  11638.    Section 11.5.1.
  11639.  
  11640.  
  11641.  11.6.3  Nesting Macro Calls
  11642.  
  11643.    Macro definitions can contain calls to other macros. Nested macro calls
  11644.    are expanded like any other macro call, but only when the outer macro is
  11645.    called.
  11646.  
  11647.    Example
  11648.  
  11649.    ex          MACRO   text,val   ; Inner macro definition
  11650.                IF2
  11651.                %OUT    The expression (text) has the value: &val
  11652.                ENDIF
  11653.                ENDM
  11654.  
  11655.    express     MACRO   expression ; Outer macro definition
  11656.                ex      <expression>,%(expression)
  11657.                ENDM
  11658.                .
  11659.                .
  11660.                .
  11661.                express <4 + 2 * 7 - 3 MOD 4>
  11662.  
  11663.    The two sample macros enable you to print the result of a complex
  11664.    expression to the screen by using the %OUT directive, even though that
  11665.    directive expects text rather than an expression (see Section 12.1,
  11666.    "Sending Messages to the Standard Output Device"). Being able to see the
  11667.    value of an expression is convenient during debugging.
  11668.  
  11669.    Both macros are necessary. The express macro calls the ex macro, using
  11670.    operators to pass the expression both as text and as the value of the
  11671.    expression. With the call in the example, the assembler sends the
  11672.    following line to the standard output:
  11673.  
  11674.    The expression (4 + 2 * 7 - 3 MOD 4) has the value: 15
  11675.  
  11676.    You could get the same output by using only the ex macro, but you would
  11677.    have to type the expression twice and supply the macro operators in the
  11678.    correct places yourself. The express macro does this for you
  11679.    automatically. Notice that expressions containing spaces must still be
  11680.    enclosed in angle brackets. Section 11.5.2, "Literal-Text Operator,"
  11681.    explains why.
  11682.  
  11683.  
  11684.  11.6.4  Redefining Macros
  11685.  
  11686.    Macros can be redefined. You do not need to purge the macro before
  11687.    redefining it. The new definition automatically replaces the old
  11688.    definition. If you redefine a macro from within the macro itself, make
  11689.    sure there are no statements or comments between the ENDM directive of the
  11690.    nested redefinition and the ENDM directive of the original macro.
  11691.  
  11692.    Example
  11693.  
  11694.    getasciiz   MACRO
  11695.                .DATA
  11696.    max         DB      80
  11697.    actual      DB      ?
  11698.    tmpstr      DB      80 DUP (?)
  11699.                .CODE
  11700.                mov     ah,0Ah
  11701.                mov     dx,OFFSET max
  11702.                int     21h
  11703.                mov     bl,actual
  11704.                xor     bh,bh
  11705.                mov     tmpstr[bx],0
  11706.    getasciiz   MACRO
  11707.                mov     ah,0Ah
  11708.                mov     dx,OFFSET max
  11709.                int     21h
  11710.                mov     bl,actual
  11711.                xor     bh,bh
  11712.                mov     tmpstr[bx],0
  11713.                ENDM
  11714.                ENDM
  11715.  
  11716.    This macro allocates data space the first time it is called, and then
  11717.    redefines itself so that it doesn't try to reallocate the data on
  11718.    subsequent calls.
  11719.  
  11720.  
  11721.  11.6.5  Avoiding Inadvertent Substitutions
  11722.  
  11723.    QuickAssembler replaces all parameters when they occur with the
  11724.    corresponding argument, even if the substitution is inappropriate. For
  11725.    example, if you use a register name, such as AX or BH, as a parameter,
  11726.    QuickAssembler replaces all occurrences of that name when it expands the
  11727.    macro. If the macro definition contains statements that use the register,
  11728.    not the parameter, the macro will be incorrectly expanded. QuickAssembler
  11729.    will not warn you about using reserved names as macro parameters.
  11730.  
  11731.    QuickAssembler does give a warning if you use a reserved name as a macro
  11732.    name. You can ignore the warning, but be aware that the reserved name will
  11733.    no longer have its original meaning. For example, if you define a macro
  11734.    called ADD, the ADD instruction will no longer be available. Your ADD
  11735.    macro takes its place.
  11736.  
  11737.  
  11738.  11.7  Managing Macros and Equates
  11739.  
  11740.    Macros and equates are often kept in a separate file and read into the
  11741.    assembler source file at assembly time. In this way, libraries of related
  11742.    macros and equates can be used by many different source files.
  11743.  
  11744.    The INCLUDE directive is used to read an include file into a source file.
  11745.    Memory can be saved by using the PURGE directive to delete the unneeded
  11746.    macros from memory.
  11747.  
  11748.  
  11749.  11.7.1  Using Include Files
  11750.  
  11751.    The INCLUDE directive inserts source code from a specified file into the
  11752.    source file from which the directive is given.
  11753.  
  11754.    Syntax
  11755.  
  11756.    INCLUDE filespec
  11757.  
  11758.    The filespec must specify an existing file containing valid assembler
  11759.    statements. When the assembler encounters an INCLUDE directive, it opens
  11760.    the specified source file and begins processing its statements. When all
  11761.    statements have been read, QuickAssembler continues with the statement
  11762.    immediately following the INCLUDE directive.
  11763.  
  11764.    The filespec can be given either as a file name, or as a complete or
  11765.    relative file specification, including drive or directory name.
  11766.  
  11767.    If a complete or relative file specification is given, QuickAssembler
  11768.    looks for the include file only in the specified directory. If a file name
  11769.    is given without a directory or drive name, QuickAssembler looks for the
  11770.    file in the following order:
  11771.  
  11772.    1. If paths are specified with the /I option, QuickAssembler looks for the
  11773.       include file in the specified directory or directories.
  11774.  
  11775.    2. QuickAssembler looks for the include file in the current directory.
  11776.  
  11777.    3. If an INCLUDE environment variable is defined, QuickAssembler looks for
  11778.       the include file in the directory or directories specified in the
  11779.       environment variable.
  11780.  
  11781.    Nested INCLUDE directives are allowed. QuickAssembler marks included
  11782.    statements with the letter "C" in assembly listings.
  11783.  
  11784.    Directories can be specified in INCLUDE path names with either the
  11785.    backslash (\) or the forward slash (/). This is for XENIX(R)
  11786.    compatibility.
  11787.  
  11788.    ──────────────────────────────────────────────────────────────────────────
  11789.    NOTE  Any standard code can be placed in an include file. However, include
  11790.    files are usually used only for macros, equates, and standard segment
  11791.    definitions. Standard procedures are usually assembled into separate
  11792.    object files and linked with the main source modules.
  11793.    ──────────────────────────────────────────────────────────────────────────
  11794.  
  11795.    Examples
  11796.  
  11797.    INCLUDE fileio.mac                   ; File name only; use with
  11798.                                         ;   /I or environment
  11799.    INCLUDE b:\include\keybd.inc         ; Complete file specification
  11800.  
  11801.    INCLUDE /usr/jons/include/stdio.mac  ; Path name in XENIX format
  11802.  
  11803.    INCLUDE masm_inc\define.inc          ; Partial path name in DOS format
  11804.                                         ;   (relative to current directory)
  11805.  
  11806.  
  11807.  11.7.2  Purging Macros from Memory
  11808.  
  11809.    The PURGE directive can be used to delete a currently defined macro from
  11810.    memory.
  11811.  
  11812.    Syntax
  11813.  
  11814.    PURGE macroname[[,macroname]]...
  11815.  
  11816.    Each macroname is deleted from memory when the directive is encountered at
  11817.    assembly time. Any subsequent call to that macro causes the assembler to
  11818.    generate an error.
  11819.  
  11820.    The PURGE directive is intended to clear memory space no longer needed by
  11821.    a macro. If a macro has been used to redefine a reserved name, the
  11822.    reserved name is restored to its previous meaning.
  11823.  
  11824.    The PURGE directive can be used to clear memory if a macro or group of
  11825.    macros is needed only for part of a source file.
  11826.  
  11827.    It is not necessary to purge a macro before redefining it. Any
  11828.    redefinition of a macro automatically purges the previous definition.
  11829.    Also, a macro can purge itself as long as the PURGE directive is on the
  11830.    last line of the macro.
  11831.  
  11832.    The PURGE directive works by redefining the macro to a null string.
  11833.    Therefore, calling a purged macro does not cause an error. The macro name
  11834.    is simply ignored.
  11835.  
  11836.    Examples
  11837.  
  11838.                GetStuff
  11839.                PURGE   GetStuff
  11840.  
  11841.    These examples call a macro and then purge it. You might need to purge
  11842.    macros in this way if your system does not have enough memory to keep all
  11843.    of the macros needed for a source file in memory at the same time.
  11844.  
  11845.  
  11846.  
  11847.  
  11848.  ────────────────────────────────────────────────────────────────────────────
  11849.  Chapter 12:  Controlling Assembly Output
  11850.  
  11851.  
  11852.    QuickAssembler has two ways of communicating results. It can write
  11853.    information to a listing or object file, or it can display messages to the
  11854.    standard output device (normally the screen).
  11855.  
  11856.    Both kinds of output can be controlled by menu commands and by source-file
  11857.    statements. This chapter explains the directives that directly control
  11858.    output through source-file statements.
  11859.  
  11860.  
  11861.  12.1  Sending Messages to the Standard Output Device
  11862.  
  11863.    The %OUT directive instructs the assembler to display text to the program
  11864.    output window.
  11865.  
  11866.    Syntax
  11867.  
  11868.    %OUT text
  11869.  
  11870.    The text can be any line of ASCII characters. If you want to display
  11871.    multiple lines, you must use a separate %OUT directive for each line.
  11872.  
  11873.    The directive is useful for displaying messages at specific points of a
  11874.    long assembly. It can be used inside conditional-assembly blocks to
  11875.    display messages when certain conditions are met.
  11876.  
  11877.    The %OUT directive generates output for both assembly passes. The IF1 and
  11878.    IF2 directives can be used for control when the directive is processed.
  11879.    Macros that enable you to output the value of expressions are shown in
  11880.    Section 11.6.3, "Nesting Macro Calls."
  11881.  
  11882.    Example
  11883.  
  11884.                IF1
  11885.                %OUT    First Pass - OK
  11886.                ENDIF
  11887.  
  11888.    This sample block could be placed at the end of a source file so that the
  11889.    message First Pass - OK would be displayed at the end of the first pass,
  11890.    but ignored on the second pass.
  11891.  
  11892.  
  11893.  12.2  Controlling Page Format in Listings
  11894.  
  11895.    QuickAssembler provides several directives for controlling the page format
  11896.    of listings. These directives include the following:
  11897.  
  11898.    Directive           Action
  11899.    ──────────────────────────────────────────────────────────────────────────
  11900.    TITLE               Sets title for listings
  11901.  
  11902.    SUBTTL              Sets title for sections in listings
  11903.  
  11904.    PAGE                Sets page length and width, and controls page and
  11905.                        section breaks
  11906.  
  11907.  
  11908.  
  11909.  12.2.1  Setting the Listing Title
  11910.  
  11911.    The TITLE directive specifies a title to be used on each page of assembly
  11912.    listings. In editor-based listing files (the default inside the QC
  11913.    environment), the title is only printed once, at the top of the file.
  11914.  
  11915.    Syntax
  11916.  
  11917.    TITLE text
  11918.  
  11919.    The text can be any combination of characters up to 60 in length. The
  11920.    title is printed flush left on the second line of each page of the
  11921.    listing.
  11922.  
  11923.    If no TITLE directive is given, the title will be blank. No more than one
  11924.    TITLE directive per module is allowed.
  11925.  
  11926.    Example
  11927.  
  11928.                TITLE Graphics Routines
  11929.  
  11930.    This example sets the listing title. A page heading that reflects this
  11931.    title is shown below:
  11932.  
  11933.    Microsoft (R) QuickC with QuickAssembler Version 2.01     9/25/89 12:00:00
  11934.    Graphics Routines
  11935.    Page     1-2
  11936.  
  11937.  
  11938.  12.2.2  Setting the Listing Subtitle
  11939.  
  11940.    The SUBTTL directive specifies the subtitle used on each page of assembly
  11941.    listings. In editor-based listing files (the default inside the QC
  11942.    environment), the subtitle is ignored.
  11943.  
  11944.    Syntax
  11945.  
  11946.    SUBTTL text
  11947.  
  11948.    The text can be any combination of characters up to 60 in length. The
  11949.    subtitle is printed flush left on the third line of the listing pages.
  11950.  
  11951.    If no SUBTTL directive is used, or if no text is given for a SUBTTL
  11952.    directive, the subtitle line is left blank.
  11953.  
  11954.    Any number of SUBTTL directives can be given in a program. Each new
  11955.    directive replaces the current subtitle with the new text. SUBTTL
  11956.    directives are often used just before a PAGE + statement, which creates a
  11957.    new section (see Section 12.2.3, "Controlling Page Breaks").
  11958.  
  11959.    Example
  11960.  
  11961.                SUBTTL Point Plotting Procedure
  11962.                PAGE    +
  11963.  
  11964.    The example above creates a section title and then creates a page break
  11965.    and a new section. A page heading that reflects this title is shown below:
  11966.  
  11967.    Microsoft (R) QuickC with QuickAssembler Version 2.01     9/25/89 12:00:00
  11968.    Graphics Routines
  11969.    Page     3-1
  11970.    Point Plotting Procedure
  11971.  
  11972.  
  11973.  12.2.3  Controlling Page Breaks
  11974.  
  11975.    The PAGE directive can be used to designate the line length and width for
  11976.    the program listing, to increment the section and adjust the section
  11977.    number accordingly, or to generate a page break in the listing. In
  11978.    editor-based listing files (the default inside the QC environment),
  11979.    page-break directives are ignored, except for the page width specifier.
  11980.  
  11981.    Syntax
  11982.  
  11983.    PAGE [[[[length]],width]]
  11984.    PAGE +
  11985.  
  11986.    If length and width are specified, the PAGE directive sets the maximum
  11987.    number of lines per page to length and the maximum number of characters
  11988.    per line to width. The length must be in the range of 10-255 lines. The
  11989.    default page length is 50 lines. The width must be in the range of 60-132
  11990.    characters. The default page width is 80 characters. With editor-based
  11991.    listing files, the default page width is 255. To specify the width without
  11992.    changing the default length, use a comma before width.
  11993.  
  11994.    If no argument is given, PAGE starts a new page in the program listing by
  11995.    copying a form-feed character to the file and generating new title and
  11996.    subtitle lines.
  11997.  
  11998.    If a plus sign follows PAGE, a page break occurs, the section number is
  11999.    incremented, and the page number is reset to 1. Program-listing page
  12000.    numbers have the following format:
  12001.  
  12002.    section-page
  12003.  
  12004.    The section is the section number within the module, and page is the page
  12005.    number within the section. By default, section and page numbers begin with
  12006.    1-1. The SUBTTL directive and the PAGE directive can be used together to
  12007.    start a new section with a new subtitle. See Section 12.2.2, "Setting the
  12008.    Listing Subtitle," for an example.
  12009.  
  12010.    Example 1
  12011.  
  12012.                PAGE
  12013.  
  12014.    Example 1 creates a page break.
  12015.  
  12016.    Example 2
  12017.  
  12018.                PAGE 58,90
  12019.  
  12020.    Example 2 sets the maximum page length to 58 lines and the maximum width
  12021.    to 90 characters.
  12022.  
  12023.    Example 3
  12024.  
  12025.                PAGE ,132
  12026.  
  12027.    Example 3 sets the maximum width to 132 characters. The current page
  12028.    length (either the default of 50 or a previously set value) remains
  12029.    unchanged.
  12030.  
  12031.    Example 4
  12032.  
  12033.                PAGE +
  12034.  
  12035.    Example 4 creates a page break, increments the current section number, and
  12036.    sets the page number to 1. For example, if the preceding page was 3-6, the
  12037.    new page would be 4-1.
  12038.  
  12039.  
  12040.  12.2.4  Naming the Module
  12041.  
  12042.    The assembler automatically uses the base file name of the source file as
  12043.    the name of the module. This name is used to identify error messages when
  12044.    you run the assembler from the command line.
  12045.  
  12046.  
  12047.  12.3  Controlling the Contents of Listings
  12048.  
  12049.    QuickAssembler provides several directives for controlling what text will
  12050.    be shown in listings. The directives that control the contents of listings
  12051.    are shown below:
  12052.  
  12053.    Directive           Action
  12054.    ──────────────────────────────────────────────────────────────────────────
  12055.    .LIST               Lists statements in program listing
  12056.  
  12057.    .XLIST              Suppresses listing of statements
  12058.  
  12059.    .LFCOND             Lists false-conditional blocks in program listing
  12060.  
  12061.    .SFCOND             Suppresses false-conditional listing
  12062.  
  12063.    .TFCOND             Toggles false-conditional listing
  12064.  
  12065.    .LALL               Includes macro expansions in program listing
  12066.  
  12067.    .SALL               Suppresses listing of macro expansions
  12068.  
  12069.    .XALL               Excludes comments from macro listing
  12070.  
  12071.  
  12072.  
  12073.  12.3.1  Suppressing and Restoring Listing Output
  12074.  
  12075.    The .LIST and .XLIST directives specify which source lines are included in
  12076.    the program listing.
  12077.  
  12078.    Syntax
  12079.  
  12080.    .LIST
  12081.    .XLIST
  12082.  
  12083.    The .XLIST directive suppresses copying of subsequent source lines to the
  12084.    program listing. The .LIST directive restores copying. The directives are
  12085.    typically used in pairs to prevent a particular section of a source file
  12086.    from being copied to the program listing.
  12087.  
  12088.    The .XLIST directive overrides other listing directives, such as .SFCOND
  12089.    or .LALL.
  12090.  
  12091.    Example
  12092.  
  12093.                .XLIST         ; Listing suspended here
  12094.                .
  12095.                .
  12096.                .
  12097.                .LIST          ; Listing resumes here
  12098.                .
  12099.                .
  12100.                .
  12101.  
  12102.  
  12103.  12.3.2  Controlling Listing of Conditional Blocks
  12104.  
  12105.    The .SFCOND, .LFCOND, and .TFCOND directives control whether
  12106.    false-conditional blocks should be included in assembly listings.
  12107.  
  12108.    Syntax
  12109.  
  12110.    .SFCOND
  12111.    .LFCOND
  12112.    .TFCOND
  12113.  
  12114.    The .SFCOND directive suppresses the listing of any subsequent conditional
  12115.    blocks whose condition is false. The .LFCOND directive restores the
  12116.    listing of these blocks. Like .LIST and .XLIST, conditional-listing
  12117.    directives can be used to suppress listing of conditional blocks in
  12118.    sections of a program.
  12119.  
  12120.    The .TFCOND directive toggles the current status of listing of conditional
  12121.    blocks. This directive can be used in conjunction with the /Sx option of
  12122.    the assembler. By default, conditional blocks are not listed on start-up.
  12123.    However, they will be listed on start-up if the /Sx option is given. This
  12124.    means that using /Sx reverses the meaning of the first .TFCOND directive
  12125.    in the source file. The /Sx option is discussed in Appendix B, Section
  12126.    B.14, "Listing False Conditionals."
  12127.  
  12128.    Example
  12129.  
  12130.    test1       EQU     0          ; Defined to make all conditionals false
  12131.  
  12132.                                   ; /Sx not used      /Sx used
  12133.                .TFCOND
  12134.                IFNDEF  test1      ; Listed            Not listed
  12135.    test2       DB      128
  12136.                ENDIF
  12137.                .TFCOND
  12138.                IFNDEF  test1      ; Not listed        Listed
  12139.    test3       DB      128
  12140.                ENDIF
  12141.                .SFCOND
  12142.                IFNDEF  test1      ; Not listed        Not listed
  12143.  
  12144.    test4       DB      128
  12145.                ENDIF
  12146.                .LFCOND
  12147.                IFNDEF  test1      ; Listed            Listed
  12148.    test5       DB      128
  12149.                ENDIF
  12150.  
  12151.    In the example above, the listing status for the first two conditional
  12152.    blocks would be different, depending on whether the /X option was used.
  12153.    The blocks with .SFCOND and .LFCOND would not be affected by the /X
  12154.    option.
  12155.  
  12156.  
  12157.  12.3.3  Controlling Listing of Macros
  12158.  
  12159.    The .LALL, .XALL, and .SALL directives control the listing of the expanded
  12160.    macro calls. The assembler always lists the full macro definition. The
  12161.    directives only affect expansion of macro calls.
  12162.  
  12163.    Syntax
  12164.  
  12165.    .LALL
  12166.    .XALL
  12167.    .SALL
  12168.  
  12169.    The .LALL directive causes QuickAssembler to list all the source
  12170.    statements in a macro expansion, including normal comments (preceded by a
  12171.    single semicolon) but not macro comments (preceded by a double semicolon).
  12172.  
  12173.    The .XALL directive causes QuickAssembler to list only those source
  12174.    statements in a macro expansion that generate code or data. For instance,
  12175.    comments, equates, and segment definitions are ignored.
  12176.  
  12177.    The .SALL directive causes QuickAssembler to suppress listing of all macro
  12178.    expansions. The listing shows the macro call, but not the source lines
  12179.    generated by the call.
  12180.  
  12181.    The .XALL directive is in effect when QuickAssembler first begins
  12182.    execution.
  12183.  
  12184.    Example
  12185.  
  12186.    tryout      MACRO   param
  12187.                                   ;; Macro comment
  12188.                                   ; Normal comment
  12189.    it          EQU     3          ; No code or data
  12190.                ASSUME  es:_DATA   ; No code or data
  12191.                DW      param      ; Generates data
  12192.                mov     ax,it      ; Generates code
  12193.                ENDM
  12194.                .
  12195.                .
  12196.                .
  12197.                .LALL
  12198.                tryout  6          ; Call with .LALL
  12199.  
  12200.                .XALL
  12201.                tryout  6          ; Call with .XALL
  12202.  
  12203.                .SALL
  12204.                tryout  6          ; Call with .SALL
  12205.  
  12206.    The macro calls in the example generate the following listing lines:
  12207.  
  12208.                                   .LALL
  12209.                                   tryout  6         ; Call with .LALL
  12210.                         1                           ; Normal comment
  12211.    = 0003               1 it      EQU     3         ; No code or data
  12212.                         1         ASSUME  es:_TEXT  ; No code or data
  12213.    0015  0006           1         DW      6         ; Generates data
  12214.    0017  B8 0003        1         mov     ax,it     ; Generates code
  12215.  
  12216.  
  12217.                                   .XALL
  12218.                                   tryout  6         ; Call with .XALL
  12219.    001A  0006           1         DW      6         ; Generates data
  12220.    001C  B8 0003        1         mov     ax,it     ; Generates code
  12221.  
  12222.  
  12223.                                   .SALL
  12224.                                   tryout  6         ; Call with .SALL
  12225.  
  12226.    Notice that the macro comment is never listed in macro expansions. Normal
  12227.    comments are listed only with the .LALL directive.
  12228.  
  12229.  
  12230.  
  12231.  ────────────────────────────────────────────────────────────────────────────
  12232.  PART 3:  Using Instructions
  12233.  
  12234.  
  12235.    Part 3 of the Programmer's Guide (comprising Chapters 13-18) explains
  12236.    how to use instructions in assembly-language source code. Instructions
  12237.    constitute the actual steps of your program and are translated into
  12238.    machine-code statements that the processor executes at run time.
  12239.  
  12240.    Part 3 is organized topically, with related instructions discussed
  12241.    together. Chapter 13 explains the instructions for moving data from one
  12242.    location to another. The instructions for performing calculations on
  12243.    numbers and bits are covered in Chapter 14.
  12244.  
  12245.    The 8086-family processors provide four major types of instructions for
  12246.    controlling program flow, as described in Chapter 15. Chapter 16
  12247.    explains the instructions and techniques for processing strings. The
  12248.    8087-family coprocessors and their instructions are explained in Chapter
  12249.    17. Finally, Chapter 18 summarizes the instructions available for
  12250.    processor control.
  12251.  
  12252.  
  12253.  
  12254.  
  12255.  ────────────────────────────────────────────────────────────────────────────
  12256.  Chapter 13:  Loading, Storing, and Moving Data
  12257.  
  12258.  
  12259.    The 8086-family processors provide several instructions for loading,
  12260.    storing, or moving various kinds of data. Among the types of transferable
  12261.    data are variables, pointers, and flags. Data can be moved to and from
  12262.    registers, memory, ports, and the stack. This chapter explains the
  12263.    instructions for moving data from one location to another.
  12264.  
  12265.  
  12266.  13.1  Transferring Data
  12267.  
  12268.    Moving data is one of the most common tasks in assembly-language
  12269.    programming. Data can be moved between registers or between memory and
  12270.    registers. Immediate data can be loaded into registers or into memory.
  12271.  
  12272.    Furthermore, all memory-to-memory operations are illegal. To move data
  12273.    from one memory location to another, you must first move the data to an
  12274.    intermediate register.
  12275.  
  12276.  
  12277.  13.1.1  Copying Data
  12278.  
  12279.    The MOV instruction is the most common method of moving data. This
  12280.    instruction can be thought of as a copy instruction, since it always
  12281.    copies the source operand to the destination operand. Immediately after a
  12282.    MOV instruction, the source and destination operands both contain the same
  12283.    value. The old value in the destination operand is destroyed.
  12284.  
  12285.    Syntax
  12286.  
  12287.    MOV {register | memory},{register | memory | immediate}
  12288.  
  12289.    Example 1
  12290.  
  12291.                mov     ax,7       ; Immediate to register
  12292.                mov     mem,7      ; Immediate to memory direct
  12293.                mov     mem[bx],7  ; Immediate to memory indirect
  12294.  
  12295.                mov     mem,ds     ; Segment register to memory
  12296.                mov     mem,ax     ; Register to memory direct
  12297.                mov     mem[bx],ax ; Register to memory indirect
  12298.  
  12299.                mov     ax,mem     ; Memory direct to register
  12300.                mov     ax,mem[bx] ; Memory indirect to register
  12301.                mov     ds,mem     ; Memory to segment register
  12302.  
  12303.                mov     ax,bx      ; Register to register
  12304.                mov     ds,ax      ; General register to segment register
  12305.                mov     ax,ds      ; Segment register to general register
  12306.  
  12307.    The statements in Example 1 illustrate each type of memory move that can
  12308.    be done with a single instruction. Example 2 illustrates several common
  12309.    types of moves that require two instructions.
  12310.  
  12311.    Example 2
  12312.  
  12313.    ; Move immediate to segment register
  12314.                mov     ax,DGROUP  ; Load immediate to general register
  12315.                mov     ds,ax      ; Store general register to segment register
  12316.  
  12317.    ; Move memory to memory
  12318.                mov     ax,mem1    ; Load memory to general register
  12319.                mov     mem2,ax    ; Store general register to memory
  12320.  
  12321.    ; Move segment register to segment register
  12322.                mov     ax,ds      ; Load segment register to general register
  12323.                mov     es,ax      ; Store general register to segment register
  12324.  
  12325.  
  12326.  13.1.2  Exchanging Data
  12327.  
  12328.    The XCHG (Exchange) instruction exchanges the data in the source and
  12329.    destination operands. Data can be exchanged between registers or between
  12330.    registers and memory.
  12331.  
  12332.    Syntax
  12333.  
  12334.    XCHG {register | memory},{register | memory}
  12335.  
  12336.    Examples
  12337.  
  12338.                xchg    ax,bx      ; Put AX in BX and BX in AX
  12339.                xchg    memory,ax  ; Put "memory" in AX and AX in "memory"
  12340.  
  12341.  
  12342.  13.1.3  Looking Up Data
  12343.  
  12344.    The XLAT (Translate) instruction is used to load data from a table in
  12345.    memory. The instruction is useful for translating bytes from one coding
  12346.    system to another.
  12347.  
  12348.    Syntax
  12349.  
  12350.    XLAT[[B]] [[[[segment:]]memory]]
  12351.  
  12352.    The BX register must contain the address of the start of the table. By
  12353.    default, the DS register contains the segment of the table, but a segment
  12354.    override can be used to specify a different segment. The operand need not
  12355.    be given except when specifying a segment override.
  12356.  
  12357.    Before the XLAT instruction is called, the AL register should contain a
  12358.    value that points into the table (the start of the table is considered 0).
  12359.    After the instruction is called, AL will contain the table value pointed
  12360.    to. For example, if AL contains 7, the 8th byte of the table will be
  12361.    placed in the AL register.
  12362.  
  12363.    ──────────────────────────────────────────────────────────────────────────
  12364.    NOTE  For compatibility with Intel 80386 mnemonics, QuickAssembler
  12365.    recognizes XLATB as a synonym for XLAT. In the Intel syntax, XLAT requires
  12366.    an operand; XLATB does not allow one. Quick-Assembler never requires an
  12367.    operand, but always allows one.
  12368.    ──────────────────────────────────────────────────────────────────────────
  12369.  
  12370.    Example
  12371.  
  12372.                ; Table of Hexadecimal digits
  12373.    hex         DB      "0123456789ABCDEF"
  12374.    convert     DB      "You pressed the key with ASCII code "
  12375.    key         DB      ?,?,"h",13,10,"$"
  12376.                .CODE
  12377.                .
  12378.                .
  12379.                .
  12380.                mov     ah,8               ; Get a key in AL
  12381.                int     21h                ; Call DOS
  12382.                mov     bx,OFFSET hex      ; Load table address
  12383.                mov     ah,al              ; Save a copy in high byte
  12384.                and     al,00001111b       ; Mask out top character
  12385.                xlat                       ; Translate
  12386.                mov     key[1],al          ; Store the character
  12387.                mov     cl,12              ; Load shift count
  12388.                shr     ax,cl              ; Shift high character into position
  12389.                xlat                       ; Translate
  12390.                mov     key,al             ; Store the character
  12391.                mov     dx,OFFSET convert  ; Load message
  12392.                mov     ah,9               ; Display it
  12393.                int     21h                ; Call DOS
  12394.  
  12395.    This example looks up hexadecimal characters in a table in order to
  12396.    convert an eight-bit binary number to a string representing a hexadecimal
  12397.    number.
  12398.  
  12399.  
  12400.  13.1.4  Transferring Flags
  12401.  
  12402.    The 8086-family processors provide instructions for loading and storing
  12403.    flags in the AH register.
  12404.  
  12405.    Syntax
  12406.  
  12407.    LAHF
  12408.    SAHF
  12409.  
  12410.    The status of the lower byte of the flags register can be saved to the AH
  12411.    register with LAHF and then later restored with SAHF. If you need to save
  12412.    and restore the entire flags register, use PUSHF and POPF, as described in
  12413.    Section 13.4.3, "Saving Flags on the Stack."
  12414.  
  12415.    SAHF is often used with a coprocessor to transfer coprocessor control
  12416.    flags to processor control flags. Section 17.7, "Controlling Program
  12417.    Flow," explains and illustrates this technique.
  12418.  
  12419.  
  12420.  13.2  Converting between Data Sizes
  12421.  
  12422.    Since moving data between registers of different sizes is illegal, you
  12423.    must take special steps if you need to extend a register value to a larger
  12424.    register or register pair.
  12425.  
  12426.    The procedure is different for signed and unsigned values. The processor
  12427.    cannot tell the difference between signed and unsigned numbers; the
  12428.    programmer has to understand this difference and program accordingly.
  12429.  
  12430.  
  12431.  13.2.1  Extending Signed Values
  12432.  
  12433.    The CBW (Convert Byte to Word) and CWD (Convert Word to Doubleword)
  12434.    instructions are provided to sign-extend values. Sign-extending means
  12435.    copying the sign bit of the unextended operand to all bits of the extended
  12436.    operand.
  12437.  
  12438.    Syntax
  12439.  
  12440.    CBW
  12441.    CWD
  12442.  
  12443.    The CBW instruction converts an 8-bit signed value in AL to a 16-bit
  12444.    signed value in AX. The CWD instruction is similar except that it
  12445.    sign-extends a 16-bit value in AX to a 32-bit value in the DX:AX register
  12446.    pair. Both instructions work only on values in the accumulator register.
  12447.  
  12448.    Example
  12449.  
  12450.                .DATA
  12451.    mem8        DB      -5
  12452.    mem16       DW      -5
  12453.                .CODE
  12454.                .
  12455.                .
  12456.                .
  12457.                mov     al,mem8    ; Load 8-bit -5 (FBh)
  12458.                cbw                ; Convert to 16-bit -5 (FFFBh) in AX
  12459.  
  12460.                mov     ax,mem16   ; Load 16-bit -5 (FFFBh)
  12461.                cwd                ; Convert to 32-bit -5 (FFFF:FFFBh)
  12462.                                   ;   in DX:AX
  12463.  
  12464.  
  12465.  13.2.2  Extending Unsigned Values
  12466.  
  12467.    To extend unsigned numbers, set the value of the upper register to 0.
  12468.  
  12469.    Example
  12470.  
  12471.                .DATA
  12472.    mem8        DB      251
  12473.    mem16       DW      251
  12474.                .CODE
  12475.                .
  12476.                .
  12477.                .
  12478.                mov     al,mem8    ; Load 251 (FBh) from 8-bit memory
  12479.                xor     ah,ah      ; Zero upper half (AH)
  12480.  
  12481.                mov     ax,mem16   ; Load 251 (FBh) from 16-bit memory
  12482.                xor     dx,dx      ; Zero upper half (DX)
  12483.  
  12484.  
  12485.  13.3  Loading Pointers
  12486.  
  12487.    The 8086-family processors provide several instructions for loading
  12488.    pointer values into registers or register pairs. They can be used to load
  12489.    either near or far pointers.
  12490.  
  12491.  
  12492.  13.3.1  Loading Near Pointers
  12493.  
  12494.    The LEA instruction loads a near pointer into a specified register.
  12495.  
  12496.    Syntax
  12497.  
  12498.    LEA register,memory
  12499.  
  12500.    The destination register may be any general-purpose register. The source
  12501.    operand may be any memory operand. The effective address of the source
  12502.    operand is placed in the destination register.
  12503.  
  12504.    The LEA instruction can be used to calculate the effective address of a
  12505.    direct memory operand, but this is usually not efficient, since the
  12506.    address of a direct memory operand is a constant known at assembly time.
  12507.    For example, the following statements have the same effect, but the second
  12508.    version is faster:
  12509.  
  12510.                lea     dx,string        ; Load effective address - slow
  12511.                mov     dx,OFFSET string ; Load offset - fast
  12512.  
  12513.    The LEA instruction is more useful for calculating the address of indirect
  12514.    memory operands:
  12515.  
  12516.                lea     dx,string[si]    ; Load effective address
  12517.  
  12518.  
  12519.  13.3.2  Loading Far Pointers
  12520.  
  12521.    The LDS and LES instructions load far pointers.
  12522.  
  12523.    Syntax
  12524.  
  12525.    LDS register,memory
  12526.    LES register,memory
  12527.  
  12528.    The memory address being pointed to is specified in the source operand,
  12529.    and the register where the offset will be stored is specified in the
  12530.    destination operand.
  12531.  
  12532.    The address must be stored in memory with the segment in the upper word
  12533.    and the offset in the lower word. The segment register where the segment
  12534.    will be stored is specified in the instruction name. For example, LDS puts
  12535.    the segment in DS, and LES puts the segment in ES. The instructions are
  12536.    often used with string instructions, as explained in Chapter 16,
  12537.    "Processing Strings."
  12538.  
  12539.    Example
  12540.  
  12541.                .DATA
  12542.    string      DB      "This is a string."
  12543.    fpstring    DD      string             ; Far pointer to string
  12544.    pointers    DD      100 DUP (?)
  12545.                .CODE
  12546.                .
  12547.                .
  12548.                .
  12549.                les     di,fpstring        ; Put address in ES:DI pair
  12550.                lds     si,pointers[bx]    ; Put address in DS:SI pair
  12551.  
  12552.  
  12553.  13.4  Transferring Data to and from the Stack
  12554.  
  12555.    A "stack" is an area of memory for storing temporary data. Unlike other
  12556.    segments in which data is stored starting from low memory, data on the
  12557.    stack is stored in reverse order starting from high memory.
  12558.  
  12559.    Initially, the stack is an uninitialized segment of a finite size. As data
  12560.    is added to the stack at run time, the stack grows downward from high
  12561.    memory to low memory. When items are removed from the stack, it shrinks
  12562.    upward from low memory to high memory.
  12563.  
  12564.    The stack has several purposes in the 8086-family processors. The CALL,
  12565.    INT, RET, and IRET instructions automatically use the stack to store the
  12566.    calling addresses of procedures and interrupts (see Sections 15.3, "Using
  12567.    Procedures," and 15.4, "Using Interrupts"). You can also use the PUSH and
  12568.    POP instructions and their variations to store values on the stack.
  12569.  
  12570.  
  12571.  13.4.1  Pushing and Popping
  12572.  
  12573.    In 8086-family processors, the SP (Stack Pointer) register always points
  12574.    to the current location in the stack. The PUSH and POP instructions use
  12575.    the SP register to keep track of the current position in the stack.
  12576.  
  12577.    The values pointed to by the BP and SP registers are relative to the SS
  12578.    (Stack Segment) register. The BP register is often used to point to the
  12579.    base of a frame of reference (a stack frame) within the stack.
  12580.  
  12581.    Syntax
  12582.  
  12583.    PUSH {register | memory}
  12584.    POP {register | memory}
  12585.    PUSH immediate                 (80186-80386 only)
  12586.  
  12587.    The PUSH instruction is used to store a two-byte operand on the stack. The
  12588.    POP instruction is used to retrieve a previously pushed value. When a
  12589.    value is pushed onto the stack, the SP register is decreased by 2. When a
  12590.    value is popped off the stack, the SP register is increased by 2. Although
  12591.    the stack always contains word values, the SP register points to bytes.
  12592.    Thus, SP changes in multiples of 2.
  12593.  
  12594.    ──────────────────────────────────────────────────────────────────────────
  12595.    NOTE  The 8088 and 8086 processors differ from later Intel processors in
  12596.    how they push and pop the SP register. If you give the statement push sp
  12597.    with the 8088 or 8086, the word pushed will be the word in SP after the
  12598.    push operation.
  12599.    ──────────────────────────────────────────────────────────────────────────
  12600.  
  12601.    Figure 13.1 illustrates how pushes and pops change the SP register.
  12602.  
  12603.    ┌────────────────────────────────────────────────────────────────────────┐
  12604.    │ This figure can be found in Section 13.4.1 of the manual               │
  12605.    └────────────────────────────────────────────────────────────────────────┘
  12606.  
  12607.    The PUSH and POP instructions are almost always used in pairs. Words are
  12608.    popped off the stack in reverse order from the order in which they are
  12609.    pushed onto the stack. You should normally do the same number of pops as
  12610.    pushes to return the stack to its original status. However, it is possible
  12611.    to return the stack to its original status by subtracting the correct
  12612.    number of words from the SP register.
  12613.  
  12614.    Values on the stack can be accessed by using indirect memory operands with
  12615.    BP as the base register.
  12616.  
  12617.    Example
  12618.  
  12619.                mov     bp,sp              ; Set stack frame
  12620.                push    ax                 ; Push first;  SP = BP + 2
  12621.                push    bx                 ; Push second; SP = BP + 4
  12622.                push    cx                 ; Push third;  SP = BP + 6
  12623.                .
  12624.                .
  12625.                .
  12626.                mov     ax,[bp+6]          ; Put third in AX
  12627.                mov     bx,[bp+4]          ; Put second in BX
  12628.                mov     cx,[bp+2]          ; Put first in CX
  12629.                .
  12630.                .
  12631.                .
  12632.                sub     sp,6               ; Restore stack pointer
  12633.                                           ;   two bytes per push
  12634.  
  12635.    80186/286/386 Only
  12636.  
  12637.    Starting with the 80186 processor, the PUSH instruction can be given with
  12638.    an immediate operand. For example, the following statement is legal on the
  12639.    80186, 80286, and 80386 processors:
  12640.  
  12641.                push    7                  ; 3 clocks on 80286
  12642.  
  12643.    This statement is faster than the following equivalent statements, which
  12644.    are required on the 8088 or 8086:
  12645.  
  12646.                mov     ax,7               ; 2 clocks on 80286
  12647.                push    ax                 ; 3 clocks on 80286
  12648.  
  12649.  
  12650.  13.4.2  Using the Stack
  12651.  
  12652.    The stack can be used to store temporary data. For example, in the
  12653.    Microsoft calling convention, the stack is used to pass arguments to a
  12654.    procedure. The arguments are pushed onto the stack before the call. The
  12655.    procedure retrieves and uses them. Then the stack is restored to its
  12656.    original position at the end of the procedure. The stack can also be used
  12657.    to store variables that are local to a procedure. Both of these techniques
  12658.    are discussed in Section 15.3, "Using Procedures."
  12659.  
  12660.    Another common use of the stack is to store temporary data when there are
  12661.    no free registers available or when a particular register must hold more
  12662.    than one value. For example, the CX register usually holds the count for
  12663.    loops. If two loops are nested, the outer count is loaded into CX at the
  12664.    start. When the inner loop starts, the outer count is pushed onto the
  12665.    stack and the inner count loaded into CX. When the inner loop finishes,
  12666.    the original count is popped back into CX.
  12667.  
  12668.    Example
  12669.  
  12670.                mov     cx,10      ; Load outer loop counter
  12671.    outer:      .
  12672.                .                  ; Start outer loop task
  12673.                .
  12674.                push    cx         ; Save outer loop value
  12675.                mov     cx,20      ; Load inner loop counter
  12676.    inner:      .
  12677.                .                  ; Do inner loop task
  12678.                .
  12679.                loop    inner
  12680.                pop     cx         ; Restore outer loop counter
  12681.                .
  12682.                .                  ; Continue outer loop task
  12683.                .
  12684.                loop    outer
  12685.  
  12686.  
  12687.  13.4.3  Saving Flags on the Stack
  12688.  
  12689.    Flags can be pushed and popped onto the stack using the PUSHF and POPF
  12690.    instructions.
  12691.  
  12692.    Syntax
  12693.  
  12694.    PUSHF
  12695.    POPF
  12696.  
  12697.    These instructions are sometimes used to save the status of flags before a
  12698.    procedure call and then to restore the same status after the procedure.
  12699.    They can also be used within a procedure to save and restore the flag
  12700.    status of the caller.
  12701.  
  12702.    Example
  12703.  
  12704.                pushf
  12705.                call    systask
  12706.                popf
  12707.  
  12708.  
  12709.  13.4.4  Saving All Registers on the Stack
  12710.  
  12711.    80186/286/386 Only
  12712.  
  12713.    Starting with the 80186 processor, the PUSHA and POPA instructions were
  12714.    implemented to push or pop all the general-purpose registers with one
  12715.    instruction.
  12716.  
  12717.    Syntax
  12718.  
  12719.    PUSHA
  12720.    POPA
  12721.  
  12722.    These instructions can be used to save the status of all registers before
  12723.    a procedure call and then to restore them after the return. Using PUSHA
  12724.    and POPA instructions is significantly faster and takes fewer bytes of
  12725.    code than pushing and popping each register individually.
  12726.  
  12727.    The registers are pushed in the following order: AX, CX, DX, BX, SP, BP,
  12728.    SI, and DI. The SP word pushed is the value before the first register is
  12729.    pushed. The registers are popped in the opposite order.
  12730.  
  12731.    Example
  12732.  
  12733.                pusha
  12734.                call    systask
  12735.                popa
  12736.  
  12737.  
  12738.  13.5  Transferring Data to and from Ports
  12739.  
  12740.    "Ports" are the gateways between hardware devices and the processor. Each
  12741.    port has a unique number through which it can be accessed. Ports can be
  12742.    used for low-level communication with devices, such as disks, the video
  12743.    display, or the keyboard. The OUT instruction is used to send data to a
  12744.    port; the IN instruction receives data from a port.
  12745.  
  12746.    Syntax
  12747.  
  12748.    IN accumulator,{portnumber | DX}
  12749.    OUT {portnumber | DX},accumulator
  12750.  
  12751.    When using the IN and OUT instructions, the number of the port can either
  12752.    be an eight-bit immediate value or the DX register. You must use DX for
  12753.    ports with a number higher than 256. The value to be received from the
  12754.    port must be in the accumulator register (AX for word values or AL for
  12755.    byte values).
  12756.  
  12757.    When using the IN instruction, the number of the port is given as the
  12758.    source operand and the value to be sent to the port is the destination
  12759.    operand. When using the OUT instruction, the number of the port is given
  12760.    as the destination operand and the value to be sent to the port is the
  12761.    source operand.
  12762.  
  12763.    In applications programming, most communication with hardware is done with
  12764.    DOS or ROM-BIOS calls. Ports are more often used in systems programming.
  12765.    Since systems programming is beyond the scope of this manual and since
  12766.    ports differ depending on hardware, the IN and OUT instructions are not
  12767.    explained in detail here.
  12768.  
  12769.    Example
  12770.  
  12771.    ; Actual values are hardware dependent
  12772.    sound       EQU     61h        ; Port to chip that controls speaker
  12773.    timer       EQU     42h        ; Port to chip that pulses speaker
  12774.    on          EQU     00000011b  ; Bits 0 and 1 turn on speaker
  12775.  
  12776.                in      al,sound   ; Get current port setting
  12777.                or      al,on      ; Turn on speaker and connect timer
  12778.                out     sound,al   ; Put value back in port
  12779.  
  12780.                mov     al,50      ; Start at 50
  12781.    sounder:    out     timer,al   ; Send byte to timer port...
  12782.  
  12783.                mov     cx,2000    ; Loop 2000 times to delay
  12784.    hold:       loop    hold
  12785.  
  12786.                dec     al         ; Go down one step
  12787.                jnz     sounder    ; Repeat for each step
  12788.  
  12789.                in      al,sound   ; Get port value
  12790.                and     al,NOT on  ; Turn it back off
  12791.                out     sound,al   ; Put it back in port
  12792.  
  12793.    This example creates a sound of ascending frequency on the IBM PC and
  12794.    IBM-compatible computers. The technique of making sound or the port values
  12795.    used may be different on other hardware.
  12796.  
  12797.    80186/286/386 Only
  12798.  
  12799.    Starting with the 80186 processor, instructions were implemented to send
  12800.    strings of data to and from ports. The instructions are INS, INSB, INSW,
  12801.    OUTS, OUTSB, and OUTSW. The operation of these instructions is much like
  12802.    the operation of other string instructions. They are discussed in Section
  12803.    16.7, "Transferring Strings to and from Ports."
  12804.  
  12805.  
  12806.  
  12807.  ────────────────────────────────────────────────────────────────────────────
  12808.  Chapter 14:  Doing Arithmetic and Bit Manipulations
  12809.  
  12810.  
  12811.    The 8086-family processors provide instructions for doing calculations on
  12812.    byte, word, and doubleword values. Operations include addition,
  12813.    subtraction, multiplication, and division. You can also do calculations at
  12814.    the bit level. This includes the AND, OR, XOR, and NOT logical operations.
  12815.    Bits can also be shifted or rotated to the right or left.
  12816.  
  12817.    This chapter tells you how to use the instructions that do calculations on
  12818.    numbers and bits.
  12819.  
  12820.  
  12821.  14.1  Adding
  12822.  
  12823.    The ADD, ADC, and INC instructions are used for adding and incrementing
  12824.    values.
  12825.  
  12826.    Syntax
  12827.  
  12828.    ADD {register | memory},{register | memory | immediate}
  12829.    ADC {register | memory},{register | memory | immediate}
  12830.    INC {register | memory}
  12831.  
  12832.    These instructions can work directly on 8-bit or 16-bit values. They can
  12833.    also be used in combination to do calculations on values that are too
  12834.    large to be held in a single register (such as 32-bit values). When used
  12835.    with AAA and DAA, they can be used to do calculations on binary coded
  12836.    decimal (BCD) numbers, as described in Section 14.5.
  12837.  
  12838.  
  12839.  14.1.1  Adding Values Directly
  12840.  
  12841.    The ADD and INC instructions are used for adding to values in registers or
  12842.    memory.
  12843.  
  12844.    The INC instruction takes a single register or memory operand. The value
  12845.    of the operand is incremented. The value is treated as an unsigned
  12846.    integer, so the carry flag is not updated for signed carries.
  12847.  
  12848.    The ADD instruction adds values given in source and destination operands.
  12849.    The destination can be either a register or a memory operand. Its contents
  12850.    will be destroyed by the operation. The source operand can be an
  12851.    immediate, memory, or register operand. Since memory-to-memory operations
  12852.    are never allowed, the source and destination operands can never both be
  12853.    memory operands.
  12854.  
  12855.    The result of the operation is stored in the source operand. The operands
  12856.    can be either 8-bit or 16-bit, but both must be the same size.
  12857.  
  12858.    An addition operation can be interpreted as addition of either signed
  12859.    numbers or unsigned numbers. It is the programmer's responsibility to
  12860.    decide how the addition should be interpreted and to take appropriate
  12861.    action if the sum is too large for the destination operand. When an
  12862.    addition overflows the possible range for signed numbers, the overflow
  12863.    flag is set. When an addition overflows the range for unsigned numbers,
  12864.    the carry flag is set.
  12865.  
  12866.    There are two ways to take action on an overflow: you can use the JO or
  12867.    JNO instruction to direct program flow to or around instructions that
  12868.    handle the overflow (see Section 15.1.2.3, "Testing Bits and Jumping").
  12869.    You can also use the INTO instruction to trigger the overflow interrupt
  12870.    (interrupt 4) if the overflow flag is set. This requires writing an
  12871.    interrupt handler for interrupt 4, since the DOS overflow routine simply
  12872.    returns without taking any action. Section 15.4.2, "Defining and
  12873.    Redefining Interrupt Routines," gives a sample of an overflow interrupt
  12874.    handler.
  12875.  
  12876.    Example
  12877.  
  12878.                .DATA
  12879.    mem8        DB      39
  12880.                .CODE
  12881.                .
  12882.                .
  12883.                .                  ;                  unsigned  signed
  12884.                mov     al,26      ; Start with register   26     26
  12885.                inc     al         ; Increment              1      1
  12886.                add     al,76      ; Add immediate       + 76     76
  12887.                                   ;                     ----   ----
  12888.                                   ;                      103    103
  12889.                add     al,mem8    ; Add memory          + 39     39
  12890.                                   ;                     ----   ----
  12891.                mov     ah,al      ; Copy to AH           142   -114+overflow
  12892.                add     al,ah      ; Add register         142
  12893.                                   ;                     ----
  12894.                                   ;                       28+carry
  12895.  
  12896.    This example shows 8-bit addition. When the sum exceeds 127, the overflow
  12897.    flag is set. A JO (Jump On Overflow) or INTO (Interrupt On Overflow)
  12898.    instruction at this point could transfer control to error-recovery
  12899.    statements. When the sum exceeds 255, the carry flag is set. A JC (Jump On
  12900.    Carry) instruction at this point could transfer control to error-recovery
  12901.    statements.
  12902.  
  12903.  
  12904.  14.1.2  Adding Values in Multiple Registers
  12905.  
  12906.    The ADC (Add with Carry) instruction makes it possible to add numbers
  12907.    larger than can be held in a single register.
  12908.  
  12909.    The ADC instruction adds two numbers in the same fashion as the ADD
  12910.    instruction, except that the value of the carry flag is included in the
  12911.    addition. If a previous calculation has set the carry flag, then 1 will be
  12912.    added to the sum of the numbers. If the carry flag is not set, the ADC
  12913.    instruction has the same effect as the ADD instruction.
  12914.  
  12915.    When adding numbers in multiple registers, the carry flag should be
  12916.    ignored for the least-significant portion, but taken into account for the
  12917.    most-significant portion. This can be done by using the ADD instruction
  12918.    for the least-significant portion and the ADC instruction for
  12919.    most-significant portion.
  12920.  
  12921.    You can add and carry repeatedly inside a loop for calculations that
  12922.    require more than two registers. Use the ADC instruction in each
  12923.    iteration, but turn off the carry flag with the CLC (Clear Carry Flag)
  12924.    instruction before entering the loop so that it will not be used for the
  12925.    first iteration. You could also do the first add outside the loop.
  12926.  
  12927.    Example
  12928.  
  12929.                .DATA
  12930.    mem32       DD      316423
  12931.                .CODE
  12932.                .
  12933.                .
  12934.                .
  12935.                mov     ax,43981             ; Load immediate     43981
  12936.                sub     dx,dx                ;   into DX:AX
  12937.                add     ax,WORD PTR mem32[0] ; Add to both     + 316423
  12938.                adc     dx,WORD PTR mem32[2] ;   memory words    ------
  12939.                                             ; Result in DX:AX   360404
  12940.  
  12941.  
  12942.  14.2  Subtracting
  12943.  
  12944.    The SUB, SBB, DEC, and NEG instructions are used for subtracting and
  12945.    decrementing values.
  12946.  
  12947.    Syntax
  12948.  
  12949.    SUB {register | memory},{register | memory | immediate}
  12950.    SBB {register | memory},{register | memory | immediate}
  12951.    DEC {register | memory}
  12952.    NEG {register | memory}
  12953.  
  12954.    These instructions can work directly on 8-bit or 16-bit values. They can
  12955.    also be used in combination to do calculations on values too large to be
  12956.    held in a single register. When used with AAA and DAA, they can be used to
  12957.    do calculations on BCD numbers, as described in Section 14.5,
  12958.    "Calculating with Binary Coded Decimals."
  12959.  
  12960.  
  12961.  14.2.1  Subtracting Values Directly
  12962.  
  12963.    The SUB and DEC instructions are used for subtracting from values in
  12964.    registers or memory. A related instruction, NEG (Negate), reverses the
  12965.    sign of a number.
  12966.  
  12967.    The DEC instruction takes a single register or memory operand. The value
  12968.    of the operand is decremented. The value is treated as an unsigned
  12969.    integer, so the carry flag is not updated for signed borrows.
  12970.  
  12971.    The NEG instruction takes a single register or memory operand. The sign of
  12972.    the value of the operand is reversed. The NEG instruction should only be
  12973.    used on signed numbers.
  12974.  
  12975.    The SUB instruction subtracts the values given in the source operand from
  12976.    the value of the destination operand. The destination can be either a
  12977.    register or a memory operand. It will be destroyed by the operation. The
  12978.    source operand can be an immediate, memory, or register operand. It will
  12979.    not be destroyed by the operation. Since memory-to-memory operations are
  12980.    never allowed, the source and destination operands cannot both be memory
  12981.    operands.
  12982.  
  12983.    The result of the operation is stored in the source operand. The operands
  12984.    can be either 8-bit or 16-bit, but both must be the same size.
  12985.  
  12986.    A subtraction operation can be interpreted as subtraction of either signed
  12987.    numbers or unsigned numbers. It is the programmer's responsibility to
  12988.    decide how the subtraction should be interpreted and to take appropriate
  12989.    action if the result is too small for the destination operand. When a
  12990.    subtraction overflows the possible range for signed numbers, the carry
  12991.    flag is set. When a subtraction underflows the range for unsigned numbers
  12992.    (becomes negative), the sign flag is set.
  12993.  
  12994.    Example
  12995.  
  12996.                .DATA
  12997.    mem8        DB      122
  12998.                .CODE
  12999.                .
  13000.                .
  13001.                .                  ;                   signed  unsigned
  13002.                mov     al,95      ; Load register         95     95
  13003.                dec     al         ; Decrement          -   1  -   1
  13004.                sub     al,23      ; Subtract immediate -  23  -  23
  13005.                                   ;                     ----   ----
  13006.                                   ;                       71     71
  13007.                sub     al,mem8    ; Subtract memory    - 122  - 122
  13008.                                   ;                     ----   ----
  13009.                                   ;                    -  51    205+sign
  13010.  
  13011.                mov     ah,119     ; Load register        119
  13012.                sub     al,ah      ;   and subtract     -  51
  13013.                                   ;                     ----
  13014.                                   ;                       86+overflow
  13015.  
  13016.    This example shows 8-bit subtraction. When the result goes below 0, the
  13017.    sign flag is set. A JS (Jump On Sign) instruction at this point could
  13018.    transfer control to error-recovery statements. When the result goes below
  13019.    -128, the carry flag is set. A JC (Jump On Carry) instruction at this
  13020.    point could transfer control to error-recovery statements.
  13021.  
  13022.  
  13023.  14.2.2  Subtracting with Values in Multiple Registers
  13024.  
  13025.    The SBB (Subtract with Borrow) instruction makes it possible to subtract
  13026.    from numbers larger than can be held in a single register.
  13027.  
  13028.    The SBB instruction subtracts two numbers in the same fashion as the SUB
  13029.    instruction except that the value of the carry flag is included in the
  13030.    subtraction. If a previous calculation has set the carry flag, then 1 will
  13031.    be subtracted from the result. If the carry flag is not set, the SBB
  13032.    instruction has the same effect as the SUB instruction.
  13033.  
  13034.    When subtracting numbers in multiple registers, the carry flag should be
  13035.    ignored for the least-significant portion, but taken into account for the
  13036.    most-significant portion. This can be done by using the SUB instruction
  13037.    for the least-significant portion and the SBB instruction for
  13038.    most-significant portions.
  13039.  
  13040.    You can subtract and borrow repeatedly inside a loop for calculations that
  13041.    require more than two registers. Use the SBB instruction in each
  13042.    iteration, but turn off the carry flag with the CLC (Clear Carry Flag)
  13043.    instruction before entering the loop so that it will not be used for the
  13044.    first iteration. You could also do the first subtraction outside the loop.
  13045.  
  13046.    Example
  13047.  
  13048.                .DATA
  13049.     mem32a     DD      316423
  13050.     mem32b     DD      156739
  13051.                .CODE
  13052.                .
  13053.                .
  13054.                .
  13055.                mov     ax,WORD PTR mem32a[0]  ; Load mem32        316423
  13056.                mov     dx,WORD PTR mem32a[2]  ;   into DX:AX
  13057.                sub     ax,WORD PTR mem32b[0]  ; Subtract low      156739
  13058.                sbb     dx,WORD PTR mem32b[2]  ;   then high       ------
  13059.                                               ; Result in DX:AX   159684
  13060.  
  13061.  
  13062.  14.3  Multiplying
  13063.  
  13064.    The MUL and IMUL instructions are used to multiply numbers. The MUL
  13065.    instruction should be used for unsigned numbers; the IMUL instruction
  13066.    should be used for signed numbers. This is the only difference between the
  13067.    two.
  13068.  
  13069.    Syntax
  13070.  
  13071.    MUL {register | memory}
  13072.    IMUL {register | memory}
  13073.  
  13074.    The multiply instructions require that one of the factors be in the
  13075.    accumulator register (AL for 8-bit numbers or AX for 16-bit numbers). This
  13076.    register is implied; it should not be specified in the source code. Its
  13077.    contents will be destroyed by the operation.
  13078.  
  13079.    The other factor to be multiplied must be specified in a single register
  13080.    or memory operand. The operand will not be destroyed by the operation,
  13081.    unless it is DX, AX, AH, or AL. A number may be squared by loading it into
  13082.    the accumulator, and then executing a multiplication instruction with the
  13083.    accumulator as the operand.
  13084.  
  13085.    Note that multiplying two 8-bit numbers will produce a 16-bit number. If
  13086.    the product is a 16-bit number, it will be placed in AX and the overflow
  13087.    and carry flags will be set.
  13088.  
  13089.    Similarly, multiplying two 16-bit numbers will produce a 32-bit number in
  13090.    the DX:AX register pair. If the product is a 32-bit number, the
  13091.    least-significant bits will be in AX, the most-significant bits will be in
  13092.    DX, and the overflow and carry flags will be set.
  13093.  
  13094.    ──────────────────────────────────────────────────────────────────────────
  13095.    NOTE  Multiplication is one of the slower operations on 8086-family
  13096.    processors (especially the 8086 and 8088). Multiplying by certain common
  13097.    constants is often faster when done by shifting bits (see Section 14.7.1,
  13098.    "Multiplying and Dividing by Constants").
  13099.    ──────────────────────────────────────────────────────────────────────────
  13100.  
  13101.    Examples
  13102.  
  13103.                .DATA
  13104.    mem16       DW      -30000
  13105.                .CODE
  13106.                .
  13107.                .
  13108.                .                  ; 8-bit unsigned multiply
  13109.                mov     al,23      ; Load AL                   23
  13110.                mov     bl,24      ; Load BL                 * 24
  13111.                mul     bl         ; Multiply BL            -----
  13112.                                   ; 16-bit signed multiply
  13113.                mov     ax,50      ; Load AX                   50
  13114.                                   ;                       -30000
  13115.                imul    mem16      ; Multiply memory        -----
  13116.                                   ; Product in DX:AX    -1500000
  13117.                                   ;   overflow and carry set
  13118.  
  13119.    80186/286/386 Only
  13120.  
  13121.    Starting with the 80186 processor, the IMUL instruction has two additional
  13122.    syntaxes that allow for 16-bit multiples that produce a 16-bit product.
  13123.  
  13124.    Syntax
  13125.  
  13126.    IMUL register16, immediate
  13127.    IMUL register16, memory16, immediate
  13128.  
  13129.    You can specify a 16-bit immediate value as the source instruction and a
  13130.    word register as the destination operand. The product appears in the
  13131.    destination operand. The 16-bit result will be placed in the destination
  13132.    operand. If the product is too large to fit in 16 bits, the carry and
  13133.    overflow flags will be set. In this context, IMUL can be used for either
  13134.    signed or unsigned multiplication, since the 16-bit product is the same.
  13135.  
  13136.    You can also specify three operands for IMUL. The first operand must be a
  13137.    16-bit register operand, the second a 16-bit memory operand, and the third
  13138.    a 16-bit immediate operand. The second and third operands are multiplied
  13139.    and the product stored in the first operand.
  13140.  
  13141.    With both of these syntaxes, the carry and overflow flags will be set if
  13142.    the product is too large to fit in 16 bits. The IMUL instruction with
  13143.    multiple operands can be used for either signed or unsigned
  13144.    multiplication, since the 16-bit product is the same in either case. If
  13145.    you need to get a 32-bit result, you must use the single-operand version
  13146.    of MUL or IMUL.
  13147.  
  13148.    Examples
  13149.  
  13150.                imul    dx,456     ; Multiply DX times 456
  13151.                imul    ax,[bx],6  ; Multiply the value pointed to by BX
  13152.                                   ;   times 6 and put the result in AX
  13153.  
  13154.  
  13155.  14.4  Dividing
  13156.  
  13157.    The DIV and IDIV instructions are used to divide integers. Both a quotient
  13158.    and a remainder are returned. The DIV instruction should be used for
  13159.    unsigned integers; the IDIV instruction should be used for signed
  13160.    integers. This is the only difference between the two.
  13161.  
  13162.    Syntax
  13163.  
  13164.    DIV {register | memory}
  13165.    IDIV {register | memory}
  13166.  
  13167.    To divide a 16-bit number by an 8-bit number, put the number to be divided
  13168.    (the dividend) in the AX register. The contents of this register will be
  13169.    destroyed by the operation. Specify the dividing number (the divisor) in
  13170.    any 8-bit memory or register operand (except AL or AH). This operand will
  13171.    not be changed by the operation. After the multiplication, the result
  13172.    (quotient) will be in AL and the remainder will be in AH.
  13173.  
  13174.    To divide a 32-bit number by a 16-bit number, put the dividend in the
  13175.    DX:AX register pair. The least-significant bits go in AX. The contents of
  13176.    these registers will be destroyed by the operation. Specify the divisor in
  13177.    any 16-bit memory or register operand (except AX or DX). This operand will
  13178.    not be changed by the operation. After the division, the quotient will be
  13179.    in AX and the remainder will be in DX.
  13180.  
  13181.    To divide a 16-bit number by a 16-bit number, you must first sign-extend
  13182.    or zero-extend (see Section 13.2, "Converting between Data Sizes") the
  13183.    dividend to 32 bits; then divide as described above. You cannot divide a
  13184.    32-bit number by another 32-bit number.
  13185.  
  13186.    If division by zero is specified, or if the quotient exceeds the capacity
  13187.    of its register (AL or AX), the processor automatically generates an
  13188.    interrupt 0. By default, the program terminates and returns to DOS. This
  13189.    problem can be handled in two ways: check the divisor before division and
  13190.    go to an error routine if you can determine it to be invalid, or write
  13191.    your own interrupt routine to replace the processor's interrupt 0 routine.
  13192.    See Section 15.4 for more information on interrupts.
  13193.  
  13194.    ──────────────────────────────────────────────────────────────────────────
  13195.    NOTE  Division is one of the slower operations on 8086-family processors
  13196.    (especially the 8086 and 8088). Dividing by common constants that are
  13197.    powers of two is often faster when done by shifting bits, as described in
  13198.    Section 14.7.1, "Multiplying and Dividing by Constants."
  13199.    ──────────────────────────────────────────────────────────────────────────
  13200.  
  13201.    Examples
  13202.  
  13203.                .DATA
  13204.  
  13205.    mem16       DW      -2000
  13206.    mem32       DD      500000
  13207.                .CODE
  13208.                .
  13209.                .                            ; Divide 16-bit unsigned by 8-bit
  13210.                .
  13211.                mov     ax,700               ; Load dividend          700
  13212.                mov     bl,36                ; Load divisor      DIV   36
  13213.                div     bl                   ; Divide BL            -----
  13214.                                             ; Quotient in AL          19
  13215.                                             ; Remainder in AH            16
  13216.  
  13217.                                             ; Divide 32-bit signed by 16-bit
  13218.  
  13219.                mov     ax,WORD PTR mem32[0] ; Load into DX:AX
  13220.                mov     dx,WORD PTR mem32[2] ;                     500000
  13221.                idiv    mem16                ;                  DIV -2000
  13222.                                             ; Divide memory       ------
  13223.                                             ; Quotient in AX        -250
  13224.                                             ; Remainder in DX             0
  13225.  
  13226.                                             ; Divide 16-bit signed by 16-bit
  13227.  
  13228.                mov     ax,WORD PTR mem16    ; Load into AX         -2000
  13229.                cwd                          ; Extend to DX:AX
  13230.                mov     bx,-421              ;                   DIV -421
  13231.                idiv    bx                   ; Divide by BX         -----
  13232.                                             ; Quotient in AX           4
  13233.                                             ; Remainder in DX            -316
  13234.  
  13235.  
  13236.  14.5  Calculating with Binary Coded Decimals
  13237.  
  13238.    The 8086-family processors provide several instructions for adjusting BCD
  13239.    numbers. The BCD format is seldom used for applications programming in
  13240.    assembly language. Programmers who wish to use BCD numbers usually use a
  13241.    high-level language. However, BCD instructions are used to develop
  13242.    compilers, function libraries, and other systems tools.
  13243.  
  13244.    Since systems programming is beyond the scope of this manual, this section
  13245.    provides only a brief overview of calculations on the two kinds of BCD
  13246.    numbers, unpacked and packed.
  13247.  
  13248.    ──────────────────────────────────────────────────────────────────────────
  13249.    NOTE  Intel mnemonics use the term "ASCII" to refer to unpacked BCD
  13250.    numbers and "decimal" to refer to packed BCD numbers. Thus AAA (ASCII
  13251.    Adjust After Addition) adjusts unpacked numbers, while DAA (Decimal Adjust
  13252.    After Addition) adjusts packed numbers.
  13253.    ──────────────────────────────────────────────────────────────────────────
  13254.  
  13255.  
  13256.  14.5.1  Unpacked BCD Numbers
  13257.  
  13258.    Unpacked BCD numbers are made up of bytes containing a single decimal
  13259.    digit in the lower four bits of each byte. The 8086-family processors
  13260.    provide instructions for adjusting unpacked values with the four
  13261.    arithmetic operations──addition, subtraction, multiplication, and
  13262.    division.
  13263.  
  13264.    To do arithmetic on unpacked BCD numbers, you must do the eight-bit
  13265.    arithmetic calculations on each digit separately. The result should always
  13266.    be in the AL register. After each operation, use the corresponding BCD
  13267.    instruction to adjust the result. The ASCII-adjust instructions do not
  13268.    take an operand. They always work on the value in the AL register.
  13269.  
  13270.    When a calculation using two one-digit values produces a two-digit result,
  13271.    the ASCII-adjust instructions put the first digit in AL and the second in
  13272.    AH. If the digit in AL needs to carry to or borrow from the digit in AH,
  13273.    the carry and auxiliary carry flags are set.
  13274.  
  13275.    The four ASCII-adjust instructions are described below:
  13276.  
  13277.    Instruction         Description
  13278.    ──────────────────────────────────────────────────────────────────────────
  13279.    AAA                 Adjusts after an addition operation. For example, to
  13280.                        add 9 and 3, use the following lines:
  13281.  
  13282.  
  13283.    mov     ax,9    ; Load 9
  13284.    mov     bx,3    ;   and 3 as unpacked BCD
  13285.    add     al,bl   ; Add 09h and 03h to get 0Ch
  13286.    aaa             ; Adjust 0Ch in AL to 02h,
  13287.                    ;   increment AH to 01h, set carry
  13288.                    ; Result 12 unpacked BCD in AX
  13289.  
  13290.    AAS                 Adjusts after a subtraction operation. For example, to
  13291.                        subtract 4 from 13, use the following lines:
  13292.  
  13293.  
  13294.    mov     ax,103h ; Load 13
  13295.    mov     bx,4    ;   and 4 as unpacked BCD
  13296.    sub     al,bl   ; Subtract 4 from 3 to get FFh (-1)
  13297.    aas             ; Adjust 0FFh in AL to 9,
  13298.                    ;   decrement AH to 0, set carry
  13299.                    ; Result 9 unpacked BCD in AX
  13300.  
  13301.    AAM                 Adjusts after a multiplication operation. Always use
  13302.                        MUL, not IMUL. For example, to multiply 9 times 3, use
  13303.                        the following lines:
  13304.  
  13305.  
  13306.    mov     ax,903h ; Load 9 and 3 as unpacked BCD
  13307.    mul     ah      ; Multiply 9 and 3 to get 1Bh
  13308.    aam             ; Adjust 1Bh in AL
  13309.                    ;   to get 27 unpacked BCD in AX
  13310.  
  13311.    AAD                 Adjusts before a division operation. Unlike other BCD
  13312.                        instructions, this one converts a BCD value to a
  13313.                        binary value before the operation. After the
  13314.                        operation, the quotient must still be adjusted by
  13315.                        using AAM. For example, to divide 25 by 2, use the
  13316.                        following lines:
  13317.  
  13318.  
  13319.    mov     ax,205h ; Load 25
  13320.    mov     bl,2    ;   and 2 as unpacked BCD
  13321.    aad             ; Adjust 0205h in AX
  13322.                    ;   to get 19h in AX
  13323.    div     bl      ; Divide by 2 to get
  13324.                    ;   quotient 0Ch in AL
  13325.                    ;   remainder 1 in AH
  13326.    aam             ; Adjust 0Ch in AL
  13327.                    ;   to 12 unpacked BCD in AX
  13328.                    ;   (remainder destroyed)
  13329.  
  13330.    Notice that the remainder is lost. If you need the remainder, save it in
  13331.    another register before adjusting the quotient. Then move it back to AL
  13332.    and adjust if necessary.
  13333.  
  13334.  
  13335.    Multidigit BCD numbers are usually processed in loops. Each digit is
  13336.    processed and adjusted in turn. In addition to their use for processing
  13337.    unpacked BCD numbers, the ASCII-adjust instructions can be used in
  13338.    routines that convert between different number bases.
  13339.  
  13340.    Example
  13341.  
  13342.                mov     al,79      ; Load 79 (04Fh)
  13343.                aam                ; Adjust to BCD (0709h)
  13344.                add     ah,'0'     ; Adjust to ASCII characters
  13345.                add     al,'0'     ;   (3739h)
  13346.                mov     dx,ax      ; Copy to DX
  13347.                xchg    dl,dh      ; Trade for most significant digit
  13348.                mov     ah,2       ; DOS display character function
  13349.                int     21h        ; Call DOS
  13350.                mov     dl,dh      ; Load least significant digit
  13351.                int     21h        ; Call DOS
  13352.  
  13353.    The example converts an eight-bit binary number to hexadecimal and
  13354.    displays it on the screen. The routine could be enhanced to handle large
  13355.    numbers.
  13356.  
  13357.  
  13358.  14.5.2  Packed BCD Numbers
  13359.  
  13360.    Packed BCD numbers are made up of bytes containing two decimal digits: one
  13361.    in the upper four bits and one in the lower four bits. The 8086-family
  13362.    processors provide instructions for adjusting packed BCD numbers after
  13363.    addition and subtraction. You must write your own routines to adjust for
  13364.    multiplication and division.
  13365.  
  13366.    To do arithmetic on packed BCD numbers, you must do the eight-bit
  13367.    arithmetic calculations on each byte separately. The result should always
  13368.    be in the AL register. After each operation, use the corresponding BCD
  13369.    instruction to adjust the result. The decimal-adjust instructions do not
  13370.    take an operand. They always work on the value in the AL register.
  13371.  
  13372.    Unlike the ASCII-adjust instructions, the decimal-adjust instructions
  13373.    never affect AH. The auxiliary carry flag is set if the digit in the lower
  13374.    four bits carries to or borrows from the digit in the upper four bits. The
  13375.    carry flag is set if the digit in the upper four bits needs to carry to or
  13376.    borrow from another byte.
  13377.  
  13378.    The decimal-adjust instructions are described below:
  13379.  
  13380.    Instruction         Description
  13381.    ──────────────────────────────────────────────────────────────────────────
  13382.    DAA                 Adjusts after an addition operation. For example, to
  13383.                        add 88 and 33, use the following lines:
  13384.  
  13385.  
  13386.                mov     ax,8833h ; Load 88 and 33 as packed BCD
  13387.                add     al,ah    ; Add 88 and 33 to get 0BBh
  13388.                daa              ; Adjust 0BBh to 121 packed BCD:
  13389.                                 ;   1 in carry and 21 in AL
  13390.  
  13391.    DAS                 Adjusts after a subtraction operation. For example, to
  13392.                        subtract 38 from 83, put 83 in AL and 38 in AH in
  13393.                        packed BCD format. Then use the following lines to
  13394.                        subtract them:
  13395.  
  13396.  
  13397.                mov     ax,3883h ; Load 83 and 38 as packed BCD
  13398.                sub     al,ah    ; Subtract 38 from 83 to get 04Bh
  13399.                das              ; Adjust 04Bh to 45 packed BCD:
  13400.                                 ;   0 in carry and 45 in AL
  13401.  
  13402.  
  13403.    Multidigit BCD numbers are usually processed in loops. Each byte is
  13404.    processed and adjusted in turn.
  13405.  
  13406.  
  13407.  14.6  Doing Logical Bit Manipulations
  13408.  
  13409.    The logical instructions do Boolean operations on individual bits. The
  13410.    AND, OR, XOR, and NOT operations are supported by the 8086-family
  13411.    instructions.
  13412.  
  13413.    AND compares two bits and sets the result if both bits are set. OR
  13414.    compares two bits and sets the result if either bit is set. XOR compares
  13415.    two bits and sets the result if the bits are different. NOT reverses a
  13416.    single bit. Table 14.1 shows a truth table for the logical operations.
  13417.  
  13418.    Table 14.1 Values Returned by Logical Operations
  13419.  
  13420.    X           Y           NOT X       X AND Y     X OR Y      X XOR Y
  13421.    ──────────────────────────────────────────────────────────────────────────
  13422.    1           1           0           1           1           0
  13423.  
  13424.    1           0           0           0           1           1
  13425.  
  13426.    0           1           1           0           1           1
  13427.  
  13428.    0           0           1           0           0           0
  13429.  
  13430.    ──────────────────────────────────────────────────────────────────────────
  13431.  
  13432.  
  13433.    The syntax of the AND, OR, and XOR instructions is the same. The only
  13434.    difference is the operation performed. For all instructions, the target
  13435.    value to be changed by the operation is placed in one operand. A mask
  13436.    showing the positions of bits to be changed is placed in the other
  13437.    operand. The format of the mask differs for each logical instruction. The
  13438.    destination operand can be register or memory. The source operand can be
  13439.    register, memory, or immediate. However, the source and destination
  13440.    operands cannot both be memory operands.
  13441.  
  13442.    Either of the values can be in either operand. However, the source operand
  13443.    will be unchanged by the operation, while the destination operand will be
  13444.    destroyed by it. Your choice of operands depends on whether you want to
  13445.    save a copy of the mask or of the target value.
  13446.  
  13447.    ──────────────────────────────────────────────────────────────────────────
  13448.    NOTE  The logical instructions should not be confused with the logical
  13449.    operators. They specify completely different behavior. The instructions
  13450.    control run-time bit calculations. The operators control assembly-time bit
  13451.    calculations. Although the instructions and operators have the same name,
  13452.    the assembler can distinguish them from context.
  13453.    ──────────────────────────────────────────────────────────────────────────
  13454.  
  13455.  
  13456.  14.6.1  AND Operations
  13457.  
  13458.    The AND instruction does an AND operation on the bits of the source and
  13459.    destination operands. The original destination operand is replaced by the
  13460.    resulting bits.
  13461.  
  13462.    Syntax
  13463.  
  13464.    AND {register | memory},{register | memory | immediate}
  13465.  
  13466.    The AND instruction can be used to clear the value of specific bits
  13467.    regardless of their current settings. To do this, put the target value in
  13468.    one operand and a mask of the bits you want to clear in the other. The
  13469.    bits of the mask should be 0 for any bit positions you want to clear and 1
  13470.    for any bit positions you want to remain unchanged.
  13471.  
  13472.    Example 1
  13473.  
  13474.                mov     ax,035h      ; Load value                  00110101
  13475.                and     ax,0FBh      ; Mask off bit 2          AND 11111011
  13476.                                     ;                             --------
  13477.                                     ; Value is now 31h            00110001
  13478.                and     ax,0F8h      ; Mask off bits 2,1,0     AND 11111000
  13479.                                     ;                             --------
  13480.                                     ; Value is now 30h            00110000
  13481.  
  13482.    Example 2
  13483.  
  13484.                mov     ah,7         ; Get character without echo
  13485.                int     21h
  13486.                and     al,11011111b ; Convert to uppercase by clearing bit 5
  13487.                cmp     al,'Y'       ; Is it Y?
  13488.                je      yes          ; If so, do Yes stuff
  13489.                .                    ;   else do No stuff
  13490.                .
  13491.    yes:        .
  13492.  
  13493.    Example 2 illustrates how to use the AND instruction to convert a
  13494.    character to uppercase. If the character is already uppercase, the AND
  13495.    instruction has no effect, since bit 5 is always clear in uppercase
  13496.    letters. If the character is lowercase, clearing bit 5 converts it to
  13497.    uppercase.
  13498.  
  13499.  
  13500.  14.6.2  OR Operations
  13501.  
  13502.    The OR instruction does an OR operation on the bits of the source and
  13503.    destination operands. The original destination operand is replaced by the
  13504.    resulting bits.
  13505.  
  13506.    Syntax
  13507.  
  13508.    OR {register | memory},{register | memory | immediate}
  13509.  
  13510.    The OR instruction can be used to set the value of specific bits
  13511.    regardless of their current settings. To do this, put the target value in
  13512.    one operand and a mask of the bits you want to clear in the other. The
  13513.    bits of the mask should be 1 for any bit positions you want to set and 0
  13514.    for any bit positions you want to remain unchanged.
  13515.  
  13516.    Example
  13517.  
  13518.                mov     ax,035h    ; Move value to register      00110101
  13519.                or      ax,08h     ; Mask on bit 3            OR 00001000
  13520.                                   ;                             --------
  13521.                                   ; Value is now 3Dh            00111101
  13522.                or      ax,07h     ; Mask on bits 2,1,0       OR 00000111
  13523.                                   ;                             --------
  13524.                                   ; Value is now 3Fh            00111111
  13525.  
  13526.    Another common use for OR is to compare an operand to 0:
  13527.  
  13528.                or      bx,bx      ; Compare to 0
  13529.                                   ;   2 bytes, 2 clocks on 8088
  13530.                jg      positive   ; BX is positive
  13531.                jl      negative   ; BX is negative
  13532.                                   ; BX is zero
  13533.  
  13534.    The first statement has the same effect as the following statement, but is
  13535.    faster and smaller:
  13536.  
  13537.                cmp     bx,0       ; 3 bytes, 3 clocks on 8088
  13538.  
  13539.  
  13540.  14.6.3  XOR Operations
  13541.  
  13542.    The XOR (Exclusive OR) instruction does an XOR operation on the bits of
  13543.    the source and destination operands. The original destination operand is
  13544.    replaced by the resulting bits.
  13545.  
  13546.    Syntax
  13547.  
  13548.    XOR {register | memory},{register | memory | immediate}
  13549.  
  13550.    The XOR instruction can be used to toggle the value of specific bits
  13551.    (reverse them from their current settings). To do this, put the target
  13552.    value in one operand and a mask of the bits you want to toggle in the
  13553.    other. The bits of the mask should be 1 for any bit positions you want to
  13554.    toggle and 0 for any bit positions you want to remain unchanged.
  13555.  
  13556.    Example
  13557.  
  13558.                mov     ax,035h    ; Move value to register      00110101
  13559.                xor     ax,08h     ; Mask on bit 3           XOR 00001000
  13560.                                   ;                             --------
  13561.                                   ; Value is now 3Dh            00111101
  13562.                xor     ax,07h     ; Mask on bits 2,1,0      XOR 00000111
  13563.                                   ;                             --------
  13564.                                   ; Value is now 3Ah            00111010
  13565.  
  13566.    Another common use for the XOR instruction is to set a register to 0:
  13567.  
  13568.                xor     cx,cx      ; 2 bytes, 3 clocks on 8088
  13569.  
  13570.    This sets the CX register to 0. When the XOR instruction takes identical
  13571.    operands, each bit cancels itself, producing 0. The statement
  13572.  
  13573.                mov     cx,0       ; 3 bytes, 4 clocks on 8088
  13574.  
  13575.    is the obvious way of doing this, but it is larger and slower. The
  13576.    statement
  13577.  
  13578.                sub     cx,cx      ; 2 bytes, 3 clocks on 8088
  13579.  
  13580.    is also smaller than the MOV version. The only advantage of using MOV is
  13581.    that it does not affect any flags.
  13582.  
  13583.  
  13584.  14.6.4  NOT Operations
  13585.  
  13586.    The NOT instruction does a NOT operation on the bits of a single operand.
  13587.    It is used to toggle the value of all bits at once.
  13588.  
  13589.    Syntax
  13590.  
  13591.    NOT {register | memory}
  13592.  
  13593.    The NOT instruction is often used to reverse the sense of a bit mask from
  13594.    masking certain bits on to masking them off. Use the NOT instruction if
  13595.    the value of the mask is not known until run time; use the NOT operator
  13596.    (see Section 9.2.1.5, "Bitwise Logical Operators") if the mask is a
  13597.    constant.
  13598.  
  13599.    Example
  13600.  
  13601.                .DATA
  13602.    masker      DB      00010000b  ; Value may change at run time
  13603.                .CODE
  13604.                .
  13605.                .
  13606.                .
  13607.                mov     ax,0D743h  ; Load 0D7h to AH, 43h to AL  01000011
  13608.                or      al,masker  ; Turn on bit 4 in AL      OR 00010000
  13609.                                   ;                             --------
  13610.                                   ; Result is 53h               01010011
  13611.  
  13612.                not     masker     ; Reverse sense of mask       11101111
  13613.                and     ah,masker  ; Turn off bit 4 in AH    AND 11010111
  13614.                                   ;                             --------
  13615.                                   ; Result is 0C7h              11000111
  13616.  
  13617.  
  13618.  14.7  Shifting and Rotating Bits
  13619.  
  13620.    The 8086-family processors provide a complete set of instructions for
  13621.    shifting and rotating bits. Bits can be moved right (toward the
  13622.    most-significant bits) or left (toward the 0 bit). Values shifted off the
  13623.    end of the operand go into the carry flag.
  13624.  
  13625.    Shift instructions move bits a specified number of places to the right or
  13626.    left. The last bit in the direction of the shift goes into the carry flag,
  13627.    and the first bit is filled with 0 or with the previous value of the first
  13628.    bit.
  13629.  
  13630.    Rotate instructions move bits a specified number of places to the right or
  13631.    left. For each bit rotated, the last bit in the direction of the rotate
  13632.    operation is moved into the first bit position at the other end of the
  13633.    operand. With some variations, the carry bit is used as an additional bit
  13634.    of the operand. Figure 14.1 illustrates the eight variations of shift and
  13635.    rotate instructions for eight-bit operands. Notice that SHL and SAL are
  13636.    identical.
  13637.  
  13638.    ┌────────────────────────────────────────────────────────────────────────┐
  13639.    │ This figure can be found in Section 14.7 of the manual                 │
  13640.    └────────────────────────────────────────────────────────────────────────┘
  13641.  
  13642.    Syntax
  13643.  
  13644.    SHL {register | memory},{CL | 1} SHR {register | memory},{CL | 1} SAL
  13645.    {register | memory},{CL | 1} SAR {register | memory},{CL | 1} ROL
  13646.    {register | memory},{CL | 1} ROR {register | memory},{CL | 1} RCL
  13647.    {register | memory},{CL | 1} RCR {register | memory},{CL | 1}
  13648.  
  13649.    The format of all the shift instructions is the same. The destination
  13650.    operand should contain the value to be shifted. It will contain the
  13651.    shifted operand after the instruction. The source operand should contain
  13652.    the number of bits to shift or rotate. It can be the immediate value 1 or
  13653.    the CL register. No other value or register is accepted on the 8088 and
  13654.    8086 processors.
  13655.  
  13656.    80186/286/386 Only
  13657.  
  13658.    Starting with the 80186 processor, eight-bit immediate values larger than
  13659.    1 can be given as the source operand for shift or rotate instructions, as
  13660.    shown below:
  13661.  
  13662.                shr     bx,4       ;  9 clocks, 3 bytes on 80286
  13663.  
  13664.    The following statements are equivalent if the program must run the 8088
  13665.    or 8086:
  13666.  
  13667.                mov     cl,4       ;  2 clocks, 3 bytes on 80286
  13668.                shr     bx,cl      ;  9 clocks, 2 bytes on 80286
  13669.                                   ; 11 clocks, 5 bytes
  13670.  
  13671.  
  13672.  14.7.1  Multiplying and Dividing by Constants
  13673.  
  13674.    Shifting right by one has the effect of dividing by two; shifting left by
  13675.    one has the effect of multiplying by two. You can take advantage of this
  13676.    to do fast multiplication and division by common constants. The easiest
  13677.    constants are the powers of two. Shifting left twice multiplies by four,
  13678.    shifting left three times multiplies by eight, and so on.
  13679.  
  13680.    SHR is used to divide unsigned numbers. SAR can be used to divide signed
  13681.    numbers, but SAR rounds negative numbers down──IDIV always rounds up. Code
  13682.    that divides by using SAR must adjust for this difference. Multiplication
  13683.    by shifting is the same for signed and unsigned numbers, so either SAL or
  13684.    SHL can be used. Both instructions do the same operation.
  13685.  
  13686.    Since the multiply and divide instructions are the slowest on the 8088 and
  13687.    8086 processors, using shifts instead can often speed operations by a
  13688.    factor of 10 or more. For example, on the 8088 or 8086 processor, the
  13689.    following statements take four clocks:
  13690.  
  13691.                xor     ah,ah      ; Clear AH
  13692.                shl     ax,1       ; Multiply byte in AL by 2
  13693.  
  13694.    The following statements have the same effect, but take between 74 and 81
  13695.    clocks on the 8088 or 8086:
  13696.  
  13697.                mov     bl,2       ; Multiply byte in AL by 2
  13698.                mul     bl
  13699.  
  13700.    The same statements take 15 clocks on the 80286. See the on-line Help
  13701.    system for complete information on timing of instructions.
  13702.  
  13703.    Shift instructions can be combined with add or subtract instructions to do
  13704.    multiplication by common constants. These operations are best put in
  13705.    macros so that they can be changed if the constants in a program change.
  13706.  
  13707.    Example 1
  13708.  
  13709.    mul_10      MACRO   factor      ; Factor must be unsigned
  13710.                mov     ax,factor   ; Load into AX
  13711.                shl     ax,1        ; AX = factor * 2
  13712.                mov     bx,ax       ; Save copy in BX
  13713.                shl     ax,1        ; AX = factor * 4
  13714.                shl     ax,1        ; AX = factor * 8
  13715.                add     ax,bx       ; AX = (factor * 8) + (factor * 2)
  13716.                ENDM                ; AX = factor * 10
  13717.  
  13718.    Example 2
  13719.  
  13720.    div_u512    MACRO   dividend    ; Dividend must be unsigned
  13721.                mov     ax,dividend ; Load into AX
  13722.                shr     ax,1        ;   AX = dividend / 2 (unsigned)
  13723.                xchg    al,ah       ; xchg is like rotate right 8
  13724.                                    ;   AL = (dividend / 2) / 256
  13725.                cbw                 ; Clear upper byte
  13726.                ENDM                ;   AX = (dividend / 512
  13727.  
  13728.  
  13729.  14.7.2  Moving Bits to the Least-Significant Position
  13730.  
  13731.    Sometimes a group of bits within an operand needs to be treated as a
  13732.    single unit──for example, to do an arithmetic operation on those bits
  13733.    without affecting other bits. This can be done by masking off the bits and
  13734.    then shifting them into the least-significant positions. After the
  13735.    arithmetic operation is done, the bits are shifted back to the original
  13736.    position and merged with the original bits by using OR. See Section
  13737.    7.2.5, "Using Record-Field Operands," for an example of this operation.
  13738.  
  13739.  
  13740.  14.7.3  Adjusting Masks
  13741.  
  13742.    Masks for logical instructions can be shifted to new bit positions. For
  13743.    example, an operand that masks off a bit or group of bits can be shifted
  13744.    to move the mask to a different position.
  13745.  
  13746.    Example
  13747.  
  13748.                .DATA
  13749.    masker      DB      00000010b  ; Mask that may change at run time
  13750.                .CODE
  13751.                .
  13752.                .
  13753.                .
  13754.                mov     cl,2       ; Rotate two at a time
  13755.                mov     bl,57h     ; Load value to be changed    01010111b
  13756.                rol     masker,cl  ; Rotate two to left          00001000b
  13757.                or      bl,masker  ; Turn on masked values       ---------
  13758.                                   ; New value is 05Fh           01011111b
  13759.                rol     masker,cl  ; Rotate two more             00100000b
  13760.                or      bl,masker  ; Turn on masked values       ---------
  13761.                                   ; New value is 07Fh           01111111b
  13762.  
  13763.    This technique is useful only if the mask value is unknown until run time.
  13764.  
  13765.  
  13766.  14.7.4  Shifting Multiword Values
  13767.  
  13768.    Sometimes it is necessary to shift a value that is too large to fit in a
  13769.    register. In this case, you can shift each part separately, passing the
  13770.    shifted bits through the carry flag. The RCR or RCL instructions must be
  13771.    used to move the carry value from the first register to the second.
  13772.  
  13773.    RCR and RCL can also be used to initialize the high or low bit of an
  13774.    operand. Since the carry flag is treated as part of the operand (like
  13775.    using a nine-bit operand), the flag value before the operation is crucial.
  13776.    The carry flag may be set by a previous instruction, or you can set it
  13777.    directly using the CLC (Clear Carry Flag), CMC (Complement Carry Flag),
  13778.    and STC (Set Carry Flag) instructions.
  13779.  
  13780.    Example
  13781.  
  13782.                .DATA
  13783.    mem32       DD      500000
  13784.                .CODE
  13785.                .
  13786.                .                            ; Divide 32-bit unsigned by 16
  13787.                .
  13788.                mov     cx,4                 ; Shift right 4        500000
  13789.    again:      shr     WORD PTR mem32[2],1  ; Shift into carry  DIV    16
  13790.                rcr     WORD PTR mem32[0],1  ; Rotate carry in      ------
  13791.                loop    again                ;                       31250
  13792.  
  13793.  
  13794.  
  13795.  ────────────────────────────────────────────────────────────────────────────
  13796.  Chapter 15:  Controlling Program Flow
  13797.  
  13798.  
  13799.    The 8086-family processors provide a variety of instructions for
  13800.    controlling the flow of a program. The four major types of program-flow
  13801.    instructions are jumps, loops, procedure calls, and interrupts.
  13802.  
  13803.    This chapter tells you how to use these instructions and how to test
  13804.    conditions for the instructions that change program flow conditionally.
  13805.  
  13806.  
  13807.  15.1  Jumping
  13808.  
  13809.    Jumps are the most direct method of changing program control from one
  13810.    location to another. At the internal level, jumps work by changing the
  13811.    value of the IP (Instruction Pointer) register from the address of the
  13812.    current instruction to a target address.
  13813.  
  13814.    Jumps can be short, near, or far. QuickAssembler automatically handles
  13815.    near and short jumps, although it may not always generate the most
  13816.    efficient code if the label being jumped to is a forward reference. The
  13817.    size and control of jumps are discussed in Section 9.4.1, "Forward
  13818.    References to Labels."
  13819.  
  13820.  
  13821.  15.1.1  Jumping Unconditionally
  13822.  
  13823.    The JMP instruction is used to jump unconditionally to a specified
  13824.    address.
  13825.  
  13826.    Syntax
  13827.  
  13828.    JMP {register | memory}
  13829.  
  13830.    The operand should contain the address to be jumped to. Unlike conditional
  13831.    jumps, whose target address must be short (within 128 bytes), the target
  13832.    address for unconditional jumps can be short, near, or far. See Section
  13833.    9.4.1 for more information on specifying the distance for conditional
  13834.    jumps.
  13835.  
  13836.    If a conditional jump must be greater than 128 bytes, the construction
  13837.    must be reorganized. This can be done by reversing the sense of the
  13838.    conditional jump and adding an unconditional jump, as shown in Example 1.
  13839.  
  13840.    Example 1
  13841.  
  13842.                cmp     ax,7       ; If AX is 7 and jump is short
  13843.                je      close      ;   then jump close
  13844.  
  13845.                cmp     ax,6       ; If AX is 6 and jump is near
  13846.                jne     close      ;   then test opposite and skip over
  13847.                jmp     distant    ; Now jump
  13848.                .
  13849.                .
  13850.                .
  13851.    close:                         ; Less than 128 bytes from jump
  13852.                .
  13853.                .
  13854.                .
  13855.    distant:                       ; More than 128 bytes from jump
  13856.  
  13857.    An unconditional jump can be used as a form of conditional jump by
  13858.    specifying the address in a register or indirect memory operand. The value
  13859.    of the operand can be calculated at run time, based on user interaction or
  13860.    other factors. You can use indirect memory operands to construct jump
  13861.    tables that work like C switch statements, BASIC ON GOTO statements, or
  13862.    Pascal case statements.
  13863.  
  13864.    Example 2
  13865.  
  13866.                .CODE
  13867.                .
  13868.                .
  13869.                .
  13870.                jmp     process            ; Jump over data
  13871.    ctl_tbl     LABEL   WORD               ;   (required in overlay procedures)
  13872.                DW      extended           ; Null key (extended code)
  13873.                DW      ctrla              ; Address of CONTROL-A key routine
  13874.                DW      ctrlb              ; Address of CONTROL-B key routine
  13875.    process:    mov     ah,8h              ; Get a key
  13876.                int     21h
  13877.                cbw                        ; Convert AL to AX
  13878.                mov     bx,ax              ; Copy
  13879.                shl     bx,1               ; Convert to address
  13880.  
  13881.                jmp     ctl_tbl[bx]        ; Jump to key routine
  13882.  
  13883.    extended:   mov     ah,8h              ; Get second key of extended
  13884.                int     21h
  13885.                .                          ; Use another jump table
  13886.                .                          ;   for extended keys
  13887.                .
  13888.    ctrla:      .                          ; CONTROL-A routine here
  13889.                .
  13890.                .
  13891.                jmp     next
  13892.  
  13893.    ctrlb:      .                          ; CONTROL-B routine here
  13894.                .
  13895.                .
  13896.                jmp     next
  13897.                .
  13898.                .
  13899.    next:       .                          ; Continue
  13900.  
  13901.    In Example 2, an indirect memory operand points to addresses of routines
  13902.    for handling different keystrokes. Notice that the jump table is placed in
  13903.    the code segment. This technique is optional in stand-alone assembler
  13904.    programs, but it may be required for procedures called from some
  13905.    languages.
  13906.  
  13907.  
  13908.  15.1.2  Jumping Conditionally
  13909.  
  13910.    The most common way of transferring control in assembly language is with
  13911.    conditional jumps. This is a two-step process: first test the condition,
  13912.    and then jump if the condition is true or continue if it is false.
  13913.  
  13914.    Syntax
  13915.  
  13916.    Jcondition label
  13917.  
  13918.    Conditional-jump instructions take a single operand containing the address
  13919.    to be jumped to. The distance from the jump instruction to the specified
  13920.    address must be short (less than 128 bytes). If a longer distance is
  13921.    specified, an error will be generated telling the distance of the jump in
  13922.    bytes. See Section 15.1.1, "Jumping Unconditionally," for information on
  13923.    arranging longer conditional jumps.
  13924.  
  13925.    Conditional-jump instructions (except JCXZ) use the status of one or more
  13926.    flags as their condition. Thus, any statement that sets a flag under
  13927.    specified conditions can be the test statement. The most common test
  13928.    statements use the CMP or TEST instructions. The jump statement can be any
  13929.    one of 31 conditional-jump instructions.
  13930.  
  13931.    Because conditional jumps cannot refer to labels more than 128 bytes away,
  13932.    they are often used in combination with unconditional jumps, which have no
  13933.    such limitation. For example, the following statement is valid as long as
  13934.    target is not far away:
  13935.  
  13936.                jz      target     ; If previous operation resulted in
  13937.                                   ;   zero, jump to target
  13938.  
  13939.    Once target becomes too distant, the following sequence must be used to
  13940.    enable a longer jump. Note that this sequence is logically equivalent to
  13941.    the example above:
  13942.  
  13943.                jnz     skip       ; If previous operation resulted in NOT zero
  13944.                                   ;   jump to "skip"
  13945.                jmp     target     ; Otherwise, jump to target
  13946.    skip:
  13947.  
  13948.    The instructions above first test for the logical inverse of the desired
  13949.    condition. If the test condition (in this case, equality to zero) is not
  13950.    true, the jump to target is avoided. Yet if a zero condition is true, the
  13951.    program falls through to the instruction jmp target, which can jump any
  13952.    distance. The effect, of course, is to jump to target if the previous
  13953.    operation resulted in zero.
  13954.  
  13955.    The problem with this technique is that if used often, you may have to
  13956.    think up a label name just to jump around one instruction. Anonymous
  13957.    labels, described in Section 6.4.2, let you avoid having to invent so
  13958.    many label names. For example, you could use an anonymous label to rewrite
  13959.    the example above:
  13960.  
  13961.                jnz     @F      ; If previous operation resulted in NOT zero,
  13962.                                ;   jump forward to next @ label
  13963.                jmp     target  ; Otherwise, jump to target
  13964.    @:
  13965.  
  13966.  
  13967.  15.1.2.1  Comparing and Jumping
  13968.  
  13969.    The CMP instruction is specifically designed to test for conditional
  13970.    jumps. It does not change the destination operand, so it can be used to
  13971.    compare two values without changing either of them. Instructions that
  13972.    change operands (such as SUB or AND) can also be used to test conditions.
  13973.  
  13974.    The CMP instruction compares two operands and sets flags based on the
  13975.    result. It is used to test the following relationships: equal; not equal;
  13976.    greater than; less than; greater than or equal; or less than or equal.
  13977.  
  13978.    Syntax
  13979.  
  13980.    CMP {register | memory},{register | memory | immediate}
  13981.  
  13982.    The destination operand can be memory or register. The source operand can
  13983.    be immediate, memory, or register. However, they cannot both be memory
  13984.    operands.
  13985.  
  13986.    The jump instructions that can be used with CMP are made up of mnemonic
  13987.    letters combined to indicate the type of jump. The letters are shown
  13988.    below:
  13989.  
  13990.    Letter              Meaning
  13991.    ──────────────────────────────────────────────────────────────────────────
  13992.    J                   Jump
  13993.  
  13994.    G                   Greater than (for unsigned comparisons)
  13995.  
  13996.    L                   Less than (for unsigned comparisons)
  13997.  
  13998.    A                   Above (for signed comparisons)
  13999.  
  14000.    B                   Below (for signed comparisons)
  14001.  
  14002.    E                   Equal
  14003.  
  14004.    N                   Not
  14005.  
  14006.  
  14007.    The mnemonic names always refer to the relationship that the first operand
  14008.    of the CMP instruction has to the second operand of the CMP instruction.
  14009.    For instance, JG tests whether the first operand is greater than the
  14010.    second. Several conditional instructions have two names. You can use
  14011.    whichever name seems more mnemonic in context.
  14012.  
  14013.    Comparisons and conditional jumps can be thought of as statements in the
  14014.    following format:
  14015.  
  14016.    IF (value1 relationship value2) THEN GOTO truelabel:
  14017.  
  14018.    Statements of this type can be coded in assembly language by using the
  14019.    following syntax:
  14020.  
  14021.    CMP value1,value2
  14022.    Jrelationship truelabel
  14023.    .
  14024.    .
  14025.    .
  14026.    truelabel:
  14027.  
  14028.    Table 15.1 lists conditional-jump instructions for each relationship and
  14029.    shows the flags that are tested in order to see if relationship is true.
  14030.  
  14031.    Table 15.1 Conditional-Jump Instructions Used after Compare
  14032.  
  14033.    Jump Condition  Signed        Jump if:    Unsigned      Jump if:
  14034.                    Compare                   Compare
  14035.    ──────────────────────────────────────────────────────────────────────────
  14036.    = Equal         JE            ZF = 1      JE            ZF = 1
  14037.  
  14038.    ╪ Not equal     JNE           ZF = 1      JNE           ZF = 1
  14039.  
  14040.    > Greater than  JG or JNLE    ZF = 0 and  JA or JNBE    CF = 0 and ZF = 0
  14041.                                  SF = OF
  14042.    <= Less than or JLE or JNG    ZF = 1 and  JBE or JNA    CF = 1 or ZF = 1
  14043.    equal                         SF ╪ OF
  14044.    < Less than     JL or JNGE    SF ╪ OF     JB or JNAE    CF = 1
  14045.  
  14046.    >= Greater than JGE or JNL    SF = OF     JAE or JNB    CF = 0
  14047.    or equal
  14048.    ──────────────────────────────────────────────────────────────────────────
  14049.  
  14050.  
  14051.    Internally, the CMP instruction is exactly the same as the SUB
  14052.    instruction, except that the destination operand is not changed. The flags
  14053.    are set according to the result that would have been generated by a
  14054.    subtraction.
  14055.  
  14056.    Example 1
  14057.  
  14058.    ; If CX is less than -20, then make DX 30, else make DX 20
  14059.  
  14060.                cmp     cx,-20     ; If signed CX is smaller than -20
  14061.                jl      less       ;   then do stuff at "less"
  14062.                mov     dx,20      ; Else set DX to 20
  14063.                jmp     skip       ; Finished
  14064.    less:       mov     dx,30      ; Then set DX to 30
  14065.    skip:
  14066.  
  14067.    Example 1 shows the basic form of conditional jumps. Notice that in
  14068.    assembly language, if-then-else constructions are usually written in the
  14069.    form if-else-then.
  14070.  
  14071.    This theme has many variations. For example, you may find it more mnemonic
  14072.    to code in the if-then-else format. However, you must then use the
  14073.    opposite jump condition, as shown in Example 2.
  14074.  
  14075.    Example 2
  14076.  
  14077.    ; If CX is greater than or equal to -20, then make DX 20, else make DX 30
  14078.  
  14079.                cmp     cx,-20     ; If signed CX is smaller than -20
  14080.                jnl     notless    ;   else do stuff at "notless"
  14081.                mov     dx,30      ; Then set DX to 30
  14082.                jmp     continue   ; Finished
  14083.    notless:    mov     dx,20      ; Else set DX to 20
  14084.    continue:
  14085.  
  14086.    The then-if-else format shown in Example 3 is often more efficient. Do the
  14087.    work for the most likely case, and then compare for the opposite
  14088.    condition. If the condition is true, you are finished.
  14089.  
  14090.    Example 3
  14091.  
  14092.    ; DX is 20, unless CX is less than -20, then make DX 30
  14093.  
  14094.                mov     dx,20      ; DX is 20
  14095.                cmp     cx,-20     ; If signed CX is greater than -20
  14096.                jge     greatequ   ;   then done
  14097.                mov     dx,30      ; Else set DX to 30
  14098.    greatequ:
  14099.  
  14100.    This example avoids the unconditional jump used in Examples 1 and 2 and
  14101.    thus is faster even if the less likely condition is true.
  14102.  
  14103.  
  14104.  15.1.2.2  Jumping Based on Flag Status
  14105.  
  14106.    The CMP instruction is the most mnemonic way to set the flags for
  14107.    conditional jumps, but any instruction that changes flags can be used as
  14108.    the test condition. The conditional-jump instructions listed below enable
  14109.    you to jump based on the condition of flags rather than on relationships
  14110.    of operands. Some of these instructions have the same effect as
  14111.    instructions listed in Table 15.1.
  14112.  
  14113.    Instruction         Action
  14114.    ──────────────────────────────────────────────────────────────────────────
  14115.    JO                  Jumps if the overflow flag is set
  14116.  
  14117.    JNO                 Jumps if the overflow flag is clear
  14118.  
  14119.    JC                  Jumps if the carry flag is set (same as JB)
  14120.  
  14121.    JNC                 Jumps if the carry flag is clear (same as JAE)
  14122.  
  14123.    JZ                  Jumps if the zero flag is set (same as JE)
  14124.  
  14125.    JNZ                 Jumps if the zero flag is clear (same as JNE)
  14126.  
  14127.    JS                  Jumps if the sign flag is set
  14128.  
  14129.    JNS                 Jumps if the sign flag is clear
  14130.  
  14131.    JP                  Jumps if the parity flag is set
  14132.  
  14133.    JNP                 Jumps if the parity flag is clear
  14134.  
  14135.    JPE                 Jumps if parity is even (parity flag set)
  14136.  
  14137.    JPO                 Jumps if parity is odd (parity flag clear)
  14138.  
  14139.    JCXZ                Jumps if CX is 0
  14140.  
  14141.  
  14142.    Notice that JCXZ is the only conditional jump based on the condition of a
  14143.    register (CX) rather than flags. Since JCXZ is usually used with loop
  14144.    instructions, it is discussed in more detail in Section 15.2, "Looping."
  14145.  
  14146.    Example 1
  14147.  
  14148.                add     ax,bx      ; Add two values
  14149.                jo      overflow   ; If value too large, adjust
  14150.                .
  14151.                .
  14152.                .
  14153.    overflow:                      ; Adjustment routine here
  14154.  
  14155.    Example 2
  14156.  
  14157.                sub     ax,dx      ; Subtract
  14158.                jnz     skip       ; If the result is not zero, continue
  14159.                call    zhandler   ;   else do special case
  14160.    skip:
  14161.  
  14162.  
  14163.  15.1.2.3  Testing Bits and Jumping
  14164.  
  14165.    Like the CMP instruction, the TEST instruction is designed to test for
  14166.    conditional jumps. However, specific bits are compared rather than entire
  14167.    operands.
  14168.  
  14169.    Syntax
  14170.  
  14171.    TEST {register | memory},{register | memory | immediate}
  14172.  
  14173.    The destination operand can be memory or register. The source operand can
  14174.    be immediate, memory, or register. However, they cannot both be memory
  14175.    operands.
  14176.  
  14177.    Normally, one of the operands is a mask in which the bits to be tested are
  14178.    the only bits set. The other operand contains the value to be tested. If
  14179.    all the bits set in the mask are clear in the operand being tested, the
  14180.    zero flag will be set. If any of the flags set in the mask are also set in
  14181.    the operand, the zero flag will be cleared.
  14182.  
  14183.    The TEST instruction is actually the same as the AND instruction, except
  14184.    that neither operand is changed. If the result of the operation is 0, the
  14185.    zero flag is set, but the 0 is not actually written to the destination
  14186.    operand.
  14187.  
  14188.    You can use the JZ and JNZ instructions to jump after the test. JE and JNE
  14189.    are the same and can be used if you find them more mnemonic.
  14190.  
  14191.    Example
  14192.  
  14193.                .DATA
  14194.    bits        DB      ?
  14195.                .CODE
  14196.                .
  14197.                .
  14198.                .
  14199.    ; If bit 2 or bit 4 is set, then call taska
  14200.  
  14201.                                     ; Assume "bits" is 0D3h       11010011
  14202.                test    bits,10100b  ; If 2 or 4 is set        AND 00010100
  14203.                jz      skip1        ; Else continue               --------
  14204.                call    taska        ; Then call taska             00010000
  14205.    skip1:                           ; Jump not taken
  14206.                .
  14207.                .
  14208.                .
  14209.    ; If bits 2 and 4 are clear, then call taskb
  14210.  
  14211.                                     ; Assume "bits" is 0E9h       11101001
  14212.               test    bits,10100b   ; If 2 and 4 are clear    AND 00010100
  14213.               jnz     skip2         ; Else continue               --------
  14214.               call    taskb         ; Then call taskb             00000000
  14215.    skip2:                           ; Jump not taken
  14216.  
  14217.  
  14218.  15.2  Looping
  14219.  
  14220.    The 8086-family processors have several instructions specifically designed
  14221.    for creating loops of repeated instructions. In addition, you can create
  14222.    loops using conditional jumps.
  14223.  
  14224.    Syntax
  14225.  
  14226.    LOOP label
  14227.    LOOPE label
  14228.    LOOPZ label
  14229.    LOOPNE label
  14230.    LOOPNZ label
  14231.    JCXZ label
  14232.  
  14233.    The LOOP instruction is used for loops with a set number of iterations.
  14234.    For example, it can be used in constructions similar to the "for" loops of
  14235.    BASIC, C, and Pascal, and the "do" loops of FORTRAN.
  14236.  
  14237.    A single operand specifies the address to jump to each time through the
  14238.    loop. The CX register is used as a counter for the number of times to
  14239.    loop. On each iteration, CX is decremented. When CX reaches 0, control
  14240.    passes to the instruction after the loop.
  14241.  
  14242.    The LOOPE, LOOPZ, LOOPNE, and LOOPNZ instructions are used in loops that
  14243.    check for a condition. For example, they can be used in constructions
  14244.    similar to the "while" loops of BASIC, C, and Pascal; the "repeat" loops
  14245.    of Pascal; and the "do" loops of C.
  14246.  
  14247.    The LOOPE (also called LOOPZ) instruction can be thought of as meaning
  14248.    "loop while equal." Similarly, the LOOPNE (also called LOOPNZ) instruction
  14249.    can be thought of as meaning "loop while not equal." A single short memory
  14250.    operand specifies the address to loop to each time through. The CX
  14251.    register can specify a maximum number of times to go through the loop. The
  14252.    CX register can be set to a number that is out of range if you do not want
  14253.    a maximum count.
  14254.  
  14255.    The JCXZ instruction is often used in loop structures. For example, it may
  14256.    be used in loops that check a condition at the start of the loop rather
  14257.    than at the end. Unlike the loop instruction, JCXZ does not decrement CX,
  14258.    so the programmer must use another statement to decrement the count. You
  14259.    can also use JCX2 with string instructions, as described in Chapter 16,
  14260.    "Processing Strings."
  14261.  
  14262.    Example 1
  14263.  
  14264.    ; For 0 to 200 do task
  14265.  
  14266.                mov     cx,200             ; Set counter
  14267.    next:       .                          ; Do the task here
  14268.                .
  14269.                .
  14270.                loop    next               ; Do again
  14271.                                           ; Continue after loop
  14272.  
  14273.    This loop has the same effect as the following statements:
  14274.  
  14275.    ; For 0 to 200, do task
  14276.  
  14277.                mov     cx,200             ; Set counter
  14278.    next:       .
  14279.                .                          ; Do the task here
  14280.                .
  14281.                dec     cx
  14282.                cmp     cx,0
  14283.                jne     next               ; Do again
  14284.                                           ; Continue after loop
  14285.  
  14286.    The first version is more efficient as well as easier to understand.
  14287.    However, there are situations in which you must use conditional-jump
  14288.    instructions rather than loop instructions. For example, conditional jumps
  14289.    are often required for loops that test several conditions.
  14290.  
  14291.    If the counter in CX is variable because of previous instructions, you
  14292.    should use the JCXZ instruction to check for 0, as shown in Example 2.
  14293.    Otherwise, if CX is 0, it will be decremented to -1 in the first iteration
  14294.    and will continue through 65,535 iterations before it reaches 0 again.
  14295.  
  14296.    Example 2
  14297.  
  14298.    ; For 0 to CX do task
  14299.  
  14300.                                           ; CX counter set previously
  14301.                jcxz    done               ; Check for 0
  14302.    next:       .                          ; Do the task here
  14303.                .
  14304.                .
  14305.                loop    next               ; Do again
  14306.    done:                                  ; Continue after loop
  14307.  
  14308.  
  14309.  15.3  Using Procedures
  14310.  
  14311.    A "procedure" is a program subdivision that typically executes a specific
  14312.    task. Once you write a procedure, you can execute it from anywhere in the
  14313.    program. This technique lets you avoid writing the same block of code over
  14314.    and over, thus saving space.
  14315.  
  14316.    Even if you execute it only once, writing a procedure can be a useful way
  14317.    of dividing a large program into manageable units. You can place a
  14318.    procedure in its own source module and test it separately.
  14319.    Assembly-language procedures are comparable to functions in C;
  14320.    subprograms, functions, and subroutines in BASIC; procedures and functions
  14321.    in Pascal; or routines and functions in FORTRAN.
  14322.  
  14323.    Two instructions control the use of assembly-language procedures. The CALL
  14324.    instruction can appear anywhere in a program. It temporarily transfers
  14325.    program control to a specified procedure. The RET instruction appears at
  14326.    the end of a procedure. It returns control back to the location that
  14327.    issued the call.
  14328.  
  14329.    These instructions use the stack to properly return from each call. The
  14330.    instruction immediately following the CALL instruction is called the
  14331.    "return address," and the procedure should return to this location when
  14332.    done. CALL pushes the return address onto the stack; RET pops this address
  14333.    off the stack and transfers program control there.
  14334.  
  14335.    Along with the RET instruction (which terminates a procedure), two
  14336.    directives help define a procedure. The PROC and ENDP directives normally
  14337.    mark the beginning and end of a procedure definition, as described in
  14338.    Section 15.3.2, "Defining Procedures."
  14339.  
  14340.    In addition, the PROC directive can save you time and effort by automating
  14341.    the following tasks:
  14342.  
  14343.    ■  Preserving register values that should not change, but that the
  14344.       procedure might otherwise alter
  14345.  
  14346.    ■  Setting up a framepointer, so that you can access parameters placed on
  14347.       the stack
  14348.  
  14349.    ■  Creating text macros, so that your source code can refer to each
  14350.       parameter by a meaningful name
  14351.  
  14352.    Section 15.3.4, "Declaring Parameters with the PROC Directive," describes
  14353.    how to use these features. Section 15.3.3, "Passing Arguments on the
  14354.    Stack," gives background information on the technique for accessing
  14355.    parameters.
  14356.  
  14357.    When you write procedures, you can create local variables, which exist
  14358.    only during execution of the procedure. The advantage of these variables
  14359.    is that they use memory dynamically, taking up space only in the procedure
  14360.    that uses them. Section 15.3.5, "Using Local Variables," describes the
  14361.    basic technique for allocating and accessing local variables. Section
  14362.    15.3.6, "Creating Locals Automatically," describes how to make the
  14363.    assembler generate the necessary code for you.
  14364.  
  14365.  
  14366.  15.3.1  Calling Procedures
  14367.  
  14368.    The CALL instruction saves the address following the instruction on the
  14369.    stack and passes control to a specified address.
  14370.  
  14371.    Syntax
  14372.  
  14373.    CALL {register | memory}
  14374.  
  14375.    The address is usually specified as a direct memory operand. However, the
  14376.    operand can also be a register or indirect memory operand containing a
  14377.    value calculated at run time. This enables you to write call tables
  14378.    similar to the jump table illustrated in Section 15.1.2.1, "Comparing and
  14379.    Jumping."
  14380.  
  14381.    Calls can be near or far. Near calls push only the offset portion of the
  14382.    calling address. Far calls push both the segment and offset. You must give
  14383.    the type of far calls to forward-referenced labels using the FAR type
  14384.    specifier and the PTR operator. For example, use the following statement
  14385.    to make a far call to a label that has not been earlier defined or
  14386.    declared external in the source code:
  14387.  
  14388.                call    FAR PTR task
  14389.  
  14390.  
  14391.  15.3.2  Defining Procedures
  14392.  
  14393.    Procedures are defined by labeling the start of the procedure and placing
  14394.    an ENDP directive at the end. The code should not fall through past the
  14395.    end of the procedure. Exit the procedure with a RET, RETF, RETN, or IRET
  14396.    instruction. There are several variations of this syntax.
  14397.  
  14398.    Syntax 1
  14399.  
  14400.    label PROC [[NEAR|FAR]] RET [[constant]] label ENDP
  14401.  
  14402.    Procedures are normally defined by using the PROC directive at the start
  14403.    of the procedure and the ENDP directive at the end. The RET instruction is
  14404.    normally placed immediately before the ENDP directive. The size of the RET
  14405.    instruction automatically matches the size defined by the PROC directive.
  14406.  
  14407.    The syntax shown is always available. In addition, there is an extended
  14408.    PROC syntax available if you use .MODEL and specify a language. The
  14409.    extended PROC syntax is explained in Section 15.3.4, "Declaring
  14410.    Parameters with the PROC Directive." These language features automate many
  14411.    of the details of accessing parameters and saving registers.
  14412.  
  14413.    Syntax 2
  14414.  
  14415.    label:
  14416.    statements
  14417.    RETN [[constant]]
  14418.  
  14419.    Syntax 3
  14420.  
  14421.    label LABEL FAR
  14422.    statements
  14423.    RETF [[constant]]
  14424.  
  14425.    The RET instruction can be extended to RETN (Return Near) or RETF (Return
  14426.    Far) to override the default size. This enables you to define and use
  14427.    procedures without the PROC and ENDP directives, as shown in Syntax 2 and
  14428.    Syntax 3, above. However, with this method, the programmer is responsible
  14429.    for making sure the size of the CALL matches the size of the RET.
  14430.  
  14431.    The RET instruction (and its RETF and RETN variations) allows a constant
  14432.    operand that specifies a number of bytes to be added to the value of the
  14433.    SP register after the return. This operand can be used to adjust for
  14434.    arguments passed to the procedure before the call, as shown in the example
  14435.    in Section 15.3.5, "Using Local Variables."
  14436.  
  14437.    Example 1
  14438.  
  14439.                call    task          ; Call is near because procedure is near
  14440.                .                     ; Return comes to here
  14441.                .
  14442.                .
  14443.    task        PROC    NEAR          ; Define "task" to be near
  14444.                .
  14445.                .                     ; Instructions of "task" go here
  14446.                .
  14447.                ret                   ; Return to instruction after call
  14448.    task        ENDP                  ; End "task" definition
  14449.  
  14450.    Example 1 shows the recommended way of making calls with QuickAssembler.
  14451.    Example 2 shows another method that programmers who are used to other
  14452.    assemblers may find more familiar.
  14453.  
  14454.    Example 2
  14455.  
  14456.                call    NEAR PTR task ; Call is declared near
  14457.                .                     ; Return comes to here
  14458.                .
  14459.                .
  14460.    task:                             ; Procedure begins with near label
  14461.                .
  14462.                .                     ; Instructions go here
  14463.                .
  14464.                retn                  ; Return declared near
  14465.  
  14466.    This method gives more direct control over procedures, but the programmer
  14467.    must make sure that calls have the same size as corresponding returns.
  14468.  
  14469.    For example, if a call is made with the statement
  14470.  
  14471.                call    NEAR PTR task
  14472.  
  14473.    the assembler does a near call. This means that one word (the offset
  14474.    following the calling address) is pushed onto the stack. If the return is
  14475.    made with the statement
  14476.  
  14477.                retf
  14478.  
  14479.    two words are popped off the stack. The first will be the offset, but the
  14480.    second will be whatever happened to be on the stack before the call. Not
  14481.    only will the popped value be meaningless, but the stack status will be
  14482.    incorrect, causing the program to fail.
  14483.  
  14484.  
  14485.  15.3.3  Passing Arguments on the Stack
  14486.  
  14487.    Procedure arguments can be passed in various ways. For example, values can
  14488.    be passed to a procedure in registers or in variables. However, the most
  14489.    common method of passing arguments is to use the stack. Microsoft
  14490.    languages have a specific convention for doing this.
  14491.  
  14492.    This section describes how a procedure accesses the parameters passed to
  14493.    it on the stack. Each parameter is accessed as an offset from BP, and you
  14494.    must calculate this offset. However, if you use the PROC directive to
  14495.    declare parameters, the assembler calculates these offsets for you and
  14496.    lets you refer to parameters by name. The next section explains how to use
  14497.    PROC this way.
  14498.  
  14499.    The arguments are pushed onto the stack before the call. After the call,
  14500.    the procedure retrieves and processes them. At the end of the procedure,
  14501.    the stack is adjusted to account for the arguments.
  14502.  
  14503.    Although the same basic method is used for all Microsoft high-level
  14504.    languages, the details vary. For instance, in some languages, pointers to
  14505.    the arguments are passed to the procedure; in others, the arguments
  14506.    themselves are passed. The order in which arguments are passed (whether
  14507.    the first argument is pushed first or last) also varies according to the
  14508.    language. Finally, in some languages, the stack is adjusted by the RET
  14509.    instruction in the called procedure; in others, the code immediately
  14510.    following the CALL instruction adjusts the stack. See Appendix A,
  14511.    "Mixed-Language Mechanics," for details on calling conventions.
  14512.  
  14513.    Example
  14514.  
  14515.    ; C-style procedure call and definition
  14516.  
  14517.                mov     ax,10      ; Load and
  14518.                push    ax         ;   push constant as third argument
  14519.                push    arg2       ; Push memory as second argument
  14520.                push    cx         ; Push register as first argument
  14521.                call    addup      ; Call the procedure
  14522.                add     sp,6       ; Destroy the pushed arguments
  14523.                .                  ;   (equivalent to three pops)
  14524.                .
  14525.                .
  14526.    addup       PROC    NEAR       ; Return address for near call
  14527.                                   ;   takes two bytes
  14528.                push    bp         ; Save base pointer - takes two bytes
  14529.                                   ;   so arguments start at 4th byte
  14530.                mov     bp,sp      ; Load stack into base pointer
  14531.                mov     ax,[bp+4]  ; Get first argument from
  14532.                                   ;   4th byte above pointer
  14533.                add     ax,[bp+6]  ; Add second argument from
  14534.                                   ;   6th byte above pointer
  14535.                add     ax,[bp+8]  ; Add third argument from
  14536.                                   ;   8th byte above pointer
  14537.                pop     bp         ; Restore BP
  14538.                ret                ; Return result in AX
  14539.    addup       ENDP
  14540.  
  14541.    The example shows one method of passing arguments to a procedure. This
  14542.    method is similar to the way procedures are called in the C language.
  14543.    Figure 15.1 shows the stack condition at key points in the process.
  14544.  
  14545.    ┌────────────────────────────────────────────────────────────────────────┐
  14546.    │ This figure can be found in Section 15.3.3 of the manual               │
  14547.    └────────────────────────────────────────────────────────────────────────┘
  14548.  
  14549.    ──────────────────────────────────────────────────────────────────────────
  14550.    NOTE  Arguments passed on the stack in assembler routines cannot be
  14551.    accessed by name in debugging commands, unless you declare parameters with
  14552.    the PROC directive, as explained in the next section.
  14553.    ──────────────────────────────────────────────────────────────────────────
  14554.  
  14555.  
  14556.  15.3.4  Declaring Parameters with the PROC Directive
  14557.  
  14558.    This section describes how to use the PROC directive in order to automate
  14559.    the parameter-accessing techniques described in the last section.
  14560.  
  14561.    The PROC directive lets you specify registers to be saved, define
  14562.    arguments to the procedure, and set up text macros so that you can refer
  14563.    to parameters by name (rather than as an offset to BP). For example, the
  14564.    following PROC directive could be placed at the beginning of a procedure
  14565.    called from BASIC that takes a single argument passed by value and that
  14566.    uses (and must save) the DI and SI registers:
  14567.  
  14568.    myproc      PROC  FAR BASIC USES DI SI, arg1:WORD
  14569.  
  14570.    Note that you must use the .MODEL directive and specify a language in
  14571.    order to use the extended features of PROC, including the lang type,
  14572.    reglist, and arguments.
  14573.  
  14574.    Syntax
  14575.  
  14576.    label PROC [[NEAR|FAR]] [[lang]] [[USES reglist]] [[arguments]]
  14577.  
  14578.    The NEAR and FAR keywords indicate whether you invoke the procedure with a
  14579.    near call or a far call, as described in Section 15.3.2, "Defining
  14580.    Procedures."
  14581.  
  14582.    The following list describes the other parts of the PROC directive:
  14583.  
  14584.    Argument            Description
  14585.    ──────────────────────────────────────────────────────────────────────────
  14586.    label               The name of the procedure. The assembler automatically
  14587.                        adds an underscore to the beginning of the name if you
  14588.                        specify C as the language in the .MODEL directive or
  14589.                        if you specify C as the lang.
  14590.  
  14591.    lang                An optional language specifier that overrides language
  14592.                        conventions specified by the .MODEL directive. The
  14593.                        language type may be C, Pascal, FORTRAN, or BASIC.
  14594.  
  14595.                        The language type determines the calling convention
  14596.                        used to access parameters and restore the stack. It
  14597.                        also determines whether an underscore is prefixed to
  14598.                        the procedure name, as required by the C naming
  14599.                        convention. Note that use of the C specifier does not
  14600.                        preserve lowercase letters in the procedure name. To
  14601.                        guarantee compatibility with C naming conventions,
  14602.                        choose Preserve Case or Preserve Extrn from the
  14603.                        Assembler Flags dialog box, or assemble with /Cl or
  14604.                        /Cx from the QCL command line.
  14605.  
  14606.    reglist             A list of registers that the procedure uses and that
  14607.                        should be saved on entry. Registers in the list must
  14608.                        be separated by blanks or tabs. The assembler
  14609.                        generates code to push these registers on the stack.
  14610.                        When you exit, the assembler generates code to pop the
  14611.                        saved register values off the stack.
  14612.  
  14613.    arguments           The list of arguments passed to the procedure on the
  14614.                        stack. See the discussion below for the syntax of the
  14615.                        argument.
  14616.  
  14617.  
  14618.    The arguments indicate each of the procedure's arguments and are separated
  14619.    from the reglist argument by a comma if there is a list of registers. Each
  14620.    argument has the following syntax:
  14621.  
  14622.    argname [[ :[[[[NEAR|FAR]]PTR]]type]]
  14623.  
  14624.    If you have more than one argument, separate each by a comma.
  14625.  
  14626.    The argname is the name of the argument. The type is the type of the
  14627.    argument and may be WORD, DWORD, QWORD, TBYTE, or the name of a structure
  14628.    defined by a STRUC structure declaration (see Chapter 6, "Defining
  14629.    Labels, Constants, and Variables" for more information about types). If
  14630.    you omit type, the default is the WORD type.
  14631.  
  14632.    The FAR, NEAR, PTR, and type arguments are all optional. If you omit all
  14633.    of them, the assembler assumes the variable is a WORD type. If you use
  14634.    only the type argument, the assembler assumes the variable has the
  14635.    indicated type.
  14636.  
  14637.    ──────────────────────────────────────────────────────────────────────────
  14638.    Note  If you are writing a routine to be called from BASIC, FORTRAN, or
  14639.    Pascal, and the routine returns a function value, you must declare an
  14640.    additional parameter if you return anything other than a two- or four-byte
  14641.    integer. See Appendix A, "Mixed-Language Mechanics," for more
  14642.    information.
  14643.    ──────────────────────────────────────────────────────────────────────────
  14644.  
  14645.    The PTR type generates debugging information so that the variable is
  14646.    treated as a pointer during debugging. The assembler assumes specific
  14647.    sizes for the variable, depending on the combination of NEAR, FAR, and PTR
  14648.    arguments you specify. The lines below show some example combinations of
  14649.    NEAR, FAR, PTR, and type:
  14650.  
  14651.    myproc      PROC var1:PTR WORD, var2:PTR DWORD
  14652.                .
  14653.                .
  14654.                .
  14655.    myproc      ENDP
  14656.  
  14657.    proc2       PROC var3:FAR PTR WORD, var4:NEAR PTR BYTE
  14658.                .
  14659.                .
  14660.                .
  14661.    proc2       ENDP
  14662.  
  14663.    If you omit NEAR or FAR, the default data size established by .MODEL is
  14664.    used. All PTR declarations are translated into a word-size variable if the
  14665.    data size is near or a doubleword variable if the data size is far.
  14666.  
  14667.    For example, the following declarations of procvar produce the same code
  14668.    for the variable name, although they generate different debugging
  14669.    information:
  14670.  
  14671.    aproc       PROC procvar:PTR WORD
  14672.  
  14673.    aproc       PROC procvar:PTR DWORD
  14674.  
  14675.    aproc       PROC procvar:PTR BYTE
  14676.  
  14677.    Specifying a particular type changes only the debugging information, not
  14678.    the code produced for accessing the argument.
  14679.  
  14680.    If you specify a NEAR PTR or FAR PTR argument, as in the declarations of
  14681.    var3 and var4, the assembler ignores the memory model you selected and
  14682.    assigns a WORD type for a NEAR PTR argument and a DWORD type for a FAR PTR
  14683.    argument.
  14684.  
  14685.    The assembler does not generate any code to get the value or values the
  14686.    pointer references; your program must still explicitly treat the argument
  14687.    as a pointer. For example, the procedure in Section 5.1 can be rewritten
  14688.    for use with BASIC so that it gets its argument by near reference (the
  14689.    BASIC default):
  14690.  
  14691.    ; Call from BASIC as a FUNCTION returning an integer
  14692.  
  14693.                .MODEL medium, basic
  14694.                .CODE
  14695.    myadd       PROC   arg1:NEAR PTR WORD, arg2:NEAR PTR WORD
  14696.  
  14697.                mov    bx,arg1  ; Load first argument
  14698.                mov    ax,[bx]
  14699.                mov    bx,arg2  ; Add second argument
  14700.                add    ax,[bx]
  14701.  
  14702.                ret
  14703.  
  14704.    myadd       ENDP
  14705.                END
  14706.  
  14707.    In the example above, even though the arguments are declared as near
  14708.    pointers, you still must code two move instructions in order to get the
  14709.    values of the arguments──the first move gets the address of the argument;
  14710.    the second move gets the argument.
  14711.  
  14712.    You can use conditional-assembly directives to make sure that your pointer
  14713.    arguments are loaded correctly for the memory model. For example, the
  14714.    following version of myadd treats the arguments as far arguments if
  14715.    necessary:
  14716.  
  14717.                .MODEL   medium,c                        ;Could be any model
  14718.                .CODE
  14719.    myadd       PROC     arg1:PTR WORD,   arf2:PTR WORD
  14720.  
  14721.                IF       @DataSize
  14722.                         les     bx,arg1                 ;Far arguments
  14723.                         mov     ax,es:[bx]
  14724.                         les     bx,arg2
  14725.                         add     ax,es:[bx]
  14726.                ELSE
  14727.                         mov     bx,arg1                 ;Near arguments
  14728.                         mov     ax,[bx]
  14729.                         mov     bx,arg2
  14730.                         add     ax,[bx]
  14731.                ENDIF
  14732.  
  14733.                ret
  14734.    myadd       ENDP
  14735.  
  14736.                END
  14737.  
  14738.    ──────────────────────────────────────────────────────────────────────────
  14739.    Note  When you use the high-level-language features and the assembler
  14740.    encounters a RET instruction, it automatically generates instructions to
  14741.    pop saved registers, remove local variables from the stack, and, if
  14742.    necessary, remove arguments. The assembler does not generate this code if
  14743.    you use a RETF or RETN instruction. It generates this code for each RET
  14744.    instruction it encounters. You can save code by having only one exit and
  14745.    jumping to it from various points.
  14746.    ──────────────────────────────────────────────────────────────────────────
  14747.  
  14748.  
  14749.  15.3.5  Using Local Variables
  14750.  
  14751.    In high-level languages, local variables are known only within a
  14752.    procedure. In Microsoft languages, these variables are usually stored on
  14753.    the stack. Assembly-language programs can use the same technique. These
  14754.    variables should not be confused with labels or variable names that are
  14755.    local to a module, as described in Chapter 8, "Creating Programs from
  14756.    Multiple Modules."
  14757.  
  14758.    ──────────────────────────────────────────────────────────────────────────
  14759.    NOTE  If your procedure has relatively few variables, you can usually
  14760.    write the most efficient code by placing these values in registers. Local
  14761.    (stack) data is efficient when you have a large amount of local data for
  14762.    the procedure.
  14763.    ──────────────────────────────────────────────────────────────────────────
  14764.  
  14765.    This section outlines the standard methods for creating local variables.
  14766.    The next section shows how to use the LOCAL directive to make the
  14767.    assembler generate local variables for you automatically. When you use
  14768.    this directive, the assembler generates the same instructions as those
  14769.    used in this section, but hides some of the details from you.
  14770.  
  14771.    If you want to use LOCAL right away, you may want to skip directly to the
  14772.    next section. However, this section gives useful background.
  14773.  
  14774.    Local variables are created by saving stack space for the variable at the
  14775.    start of the procedure. The variable can then be accessed by its position
  14776.    in the stack. At the end of the procedure, the stack pointer is restored
  14777.    to restore the memory used by local variables.
  14778.  
  14779.    Example
  14780.  
  14781.                push    ax         ; Push one argument
  14782.                call    task       ; Call
  14783.                .
  14784.                .
  14785.                .
  14786.    arg         EQU     <[bp+4]>   ; Name for argument
  14787.    loc         EQU     <[bp-2]>   ; Name for local variable
  14788.  
  14789.    task        PROC    NEAR
  14790.                push    bp         ; Save base pointer
  14791.                mov     bp,sp      ; Load stack into base pointer
  14792.                sub     sp,2       ; Save two bytes for local variable
  14793.                .
  14794.                .
  14795.                .
  14796.                mov     loc,3      ; Initialize local variable
  14797.                add     ax,loc     ; Add local variable to AX
  14798.                sub     arg,ax     ; Subtract local from argument
  14799.                .                  ; Use "loc" and "arg" in other operations
  14800.                .
  14801.                .
  14802.                mov     sp,bp      ; Adjust for stack variable
  14803.                pop     bp         ; Restore base
  14804.                ret     2          ; Return result in AX and pop
  14805.    task        ENDP               ;   two bytes to adjust stack
  14806.  
  14807.    In this example, two bytes are subtracted from the SP register to make
  14808.    room for a local word variable. This variable can then be accessed as
  14809.    [bp-2]. In the example, this value is given the name loc with a text
  14810.    equate. Notice that the instruction mov sp,bp is given at the end to
  14811.    restore the original value of SP. The statement is only required if the
  14812.    value of SP is changed inside the procedure (usually by allocating local
  14813.   variables). The argument passed to the procedure is returned with the
  14814.   RET instruction. Contrast this to the example in Section 15.3.3,
  14815.  "Passing Arguments on the Stack," in which the calling code adjusts for
  14816.   the argument. Figure 15.2 shows the state of the stack at key points in
  14817.   the process.
  14818.  
  14819.    ┌────────────────────────────────────────────────────────────────────────┐
  14820.    │ This figure can be found in Section 15.3.5 of the manual               │
  14821.    └────────────────────────────────────────────────────────────────────────┘
  14822.  
  14823.    ──────────────────────────────────────────────────────────────────────────
  14824.    NOTE  Local variables created in assembler routines cannot be accessed by
  14825.    name with debugging commands, unless you declare local variables with the
  14826.    LOCAL directive, as explained in the next section.
  14827.    ──────────────────────────────────────────────────────────────────────────
  14828.  
  14829.  
  14830.  15.3.6  Creating Locals Automatically
  14831.  
  14832.    This section describes how to automate the techniques for local-variable
  14833.    creation described in the last section.
  14834.  
  14835.    You can use the LOCAL directive to save time and effort when working with
  14836.    local variables. When you use this directive, simply list the variables
  14837.    you want to create, giving a type for each one. The assembler calculates
  14838.    how much space is required on the stack. It also generates instructions to
  14839.    properly decrement SP (as described in the previous section) and to later
  14840.    reset SP when you return from the procedure.
  14841.  
  14842.    The LOCAL directive can only be used inside procedures created with the
  14843.    extended PROC directive. This means that you must first use .MODEL and
  14844.    specify a language.
  14845.  
  14846.    When you create local variables this way, your source code can then refer
  14847.    to each local variable by name rather than as an offset. Moreover, the
  14848.    assembler generates debugging information for each local variable, so that
  14849.    you can enter the name of the local variable as part of a Watch
  14850.    expression.
  14851.  
  14852.    The procedure in Section 15.3.5 can be generated more simply with the
  14853.    following code:
  14854.  
  14855.    task        PROC        NEAR     arg:WORD
  14856.                LOCAL       loc:WORD
  14857.                .
  14858.                .
  14859.                .
  14860.                mov         loc,3         ; Initialize local variable
  14861.                add         ax,loc        ; Add local variable to AX
  14862.                sub         arg,ax        ; Subtract local from argument
  14863.                .                         ; Use "Loc" and "arg" in other operat
  14864.                .
  14865.                .
  14866.                ret
  14867.    task        ENDP
  14868.  
  14869.    The LOCAL directive has the following syntax:
  14870.  
  14871.    LOCAL vardef [[,vardef]]...
  14872.  
  14873.    Each vardef has the form:
  14874.  
  14875.    label[[[count]]][[:[[[[NEAR | FAR]]PTR]]type]]]]...
  14876.  
  14877.    The LOCAL directive arguments are as follows:
  14878.  
  14879.    Argument            Description
  14880.    ──────────────────────────────────────────────────────────────────────────
  14881.    label               The name given to the local variable. The assembler
  14882.                        automatically defines a text macro you may use to
  14883.                        access the variable.
  14884.  
  14885.    count               The number of elements of this name and type to
  14886.                        allocate on the stack. Using count allows you to
  14887.                        allocate a simple array on the stack. The brackets
  14888.                        around count are required. If this field is omitted,
  14889.                        one data object is assumed.
  14890.  
  14891.    type                The type of variable to allocate. The type argument
  14892.                        may be one of the following: WORD, DWORD, QWORD,
  14893.                        TBYTE, or the name of a structure defined by a STRUC
  14894.                        structure declaration.
  14895.  
  14896.  
  14897.    The assembler sets aside space on the stack, following the same rules as
  14898.    for procedure arguments.
  14899.  
  14900.    The assembler does not initialize local variables. Your program must
  14901.    include code to perform any necessary initializations. For example, the
  14902.    following code fragment sets up a local array and initializes it to zero:
  14903.  
  14904.    arraysz     EQU   20
  14905.  
  14906.    aproc       PROC
  14907.                LOCAL var1[arraysz]:WORD, var2:WORD
  14908.                .
  14909.                .
  14910.                .
  14911.    ; Initialize local array to zero
  14912.                mov   cx,arraysz
  14913.                xor   ax,ax
  14914.                xor   di,di           ; Use di as array index
  14915.    repeat:     mov   var1[di],ax
  14916.                inc   di
  14917.                inc   di
  14918.                loop  repeat
  14919.    ; Use the array...
  14920.                .
  14921.                .
  14922.                .
  14923.                ret
  14924.    aproc
  14925.  
  14926.  
  14927.  15.3.7  Variable Scope
  14928.  
  14929.    When you use the extended form of the .MODEL directive, the assembler
  14930.    makes all identifiers inside a procedure local to the procedure. Labels
  14931.    ending with a colon (:), procedure arguments, and local variables declared
  14932.    in a LOCAL directive are undefined outside of the procedure. Variables
  14933.    defined outside of any procedure are available inside a procedure. For
  14934.    example, in the following fragment, var1 can be used in proc1 and proc2,
  14935.    while var2──because it is defined in proc2──is not available to proc1:
  14936.  
  14937.              .MODEL medium,c
  14938.                .DATA
  14939.    var1        DW     256          ; Available to proc1 and proc2
  14940.  
  14941.                .CODE
  14942.    proc1       PROC
  14943.                .
  14944.                .
  14945.                .
  14946.    exit:       ret
  14947.    proc1       ENDP
  14948.  
  14949.    proc2       PROC
  14950.                LOCAL   var2:WORD   ; This var2 only available in proc2
  14951.                .
  14952.                .
  14953.                .
  14954.    exit:       ret
  14955.    proc2       ENDP
  14956.  
  14957.    If proc1 contained a LOCAL directive defining var2, that var2 would be a
  14958.    completely different variable than the var2 in proc2.
  14959.  
  14960.    Notice that both procedures contain the label exit. Because labels are
  14961.    local when you use the language option on the .MODEL directive, you may
  14962.    use the same labels in different procedures. You can make a label in a
  14963.    procedure global (make it available outside the procedure) by ending it
  14964.    with two colons:
  14965.  
  14966.    proc3       PROC
  14967.                .
  14968.                .
  14969.                .
  14970.    label1::
  14971.                .
  14972.                .
  14973.                .
  14974.    proc3       ENDP
  14975.  
  14976.    In the preceding example, label1 is available throughout the file
  14977.    containing proc3.
  14978.  
  14979.  
  14980.  15.3.8  Setting Up Stack Frames
  14981.  
  14982.    80186/286/386 Only
  14983.  
  14984.    Starting with the 80186 processor, the ENTER and LEAVE instructions are
  14985.    provided for setting up a stack frame. These instructions do the same
  14986.    thing as the multiple instructions at the start and end of procedures in
  14987.    the Microsoft calling conventions (see the examples in Section 15.3.3,
  14988.    "Passing Arguments on the Stack").
  14989.  
  14990.    The PROC statement takes advantage of these instructions if you enable the
  14991.    extended instruction set with the .186 or .286 directive.
  14992.  
  14993.    Syntax
  14994.  
  14995.    ENTER framesize, nestinglevel
  14996.    statements
  14997.    LEAVE
  14998.  
  14999.    The ENTER instruction takes two constant operands. The framesize (a 16-bit
  15000.    constant) specifies the number of bytes to reserve for local variables.
  15001.    The nestinglevel (an 8-bit constant) specifies the level at which the
  15002.    procedure is nested. This operand should always be 0 when writing
  15003.    procedures for BASIC, C, and FORTRAN. The nestinglevel can be greater than
  15004.    0 with Pascal and other languages that enable procedures to access the
  15005.    local variables of calling procedures.
  15006.  
  15007.    The LEAVE instruction reverses the effect of the last ENTER instruction by
  15008.    restoring BP and SP to their values before the procedure call.
  15009.  
  15010.    Example 1
  15011.  
  15012.    task        PROC    NEAR
  15013.                enter   6,0        ; Set stack frame and reserve 6
  15014.                .                  ;   bytes for local variables
  15015.                .                  ; Do task here
  15016.                .
  15017.                leave              ; Restore stack frame
  15018.                ret                ; Return
  15019.    task        ENDP
  15020.  
  15021.    Example 1 has the same effect as the code in Example 2.
  15022.  
  15023.    Example 2
  15024.  
  15025.    task        PROC    NEAR
  15026.                push    bp         ; Save base pointer
  15027.                mov     bp,sp      ; Load stack into base pointer
  15028.                sub     sp,6       ; Reserve 6 bytes for local variables
  15029.                .
  15030.                .                  ; Do task here
  15031.                .
  15032.  
  15033.                mov     sp,bp      ; Restore stack pointer
  15034.                pop     bp         ; Restore base
  15035.                ret                ; Return
  15036.    task        ENDP
  15037.  
  15038.    The code in Example 1 takes fewer bytes, but is slightly slower. See
  15039.    on-line Help on instructions for exact comparisons of size and timing.
  15040.  
  15041.  
  15042.  15.4  Using Interrupts
  15043.  
  15044.    "Interrupts" are a special form of routines that are called by number
  15045.    instead of by address. They can be initiated by hardware devices as well
  15046.    as by software. Hardware interrupts are called automatically whenever
  15047.    certain events occur in the hardware.
  15048.  
  15049.    Interrupts can have any number from 0 to 255. Most of the interrupts with
  15050.    lower numbers are reserved for use by the processor, DOS, or the ROM BIOS.
  15051.  
  15052.    The programmer can call existing interrupts with the INT instruction.
  15053.    Interrupt routines can also be defined or redefined to be called later.
  15054.    For example, an interrupt routine that is called automatically by a
  15055.    hardware device can be redefined so that its action is different.
  15056.  
  15057.    DOS defines several interrupt handlers. Two that are sometimes used by
  15058.    applications programmers are listed below:
  15059.  
  15060.    Interrupt           Description
  15061.    ──────────────────────────────────────────────────────────────────────────
  15062.    0                   Divide overflow. Called automatically when the
  15063.                        quotient of a divide operation is too large for the
  15064.                        source operand or when a divide by zero is attempted.
  15065.  
  15066.    4                   Overflow. Called by the INTO instruction if the
  15067.                        overflow flag is set.
  15068.  
  15069.  
  15070.    Interrupt 21H is the normal method of using DOS functions. To call a
  15071.    function, place the function number in AH, put arguments in registers as
  15072.    appropriate, then call the interrupt. For complete documentation of DOS
  15073.    functions, see the Microsoft MS-DOS Programmer's Reference, one of the
  15074.    many other books on DOS functions, or the on-line Help system.
  15075.  
  15076.    DOS has several other interrupts, but they should not normally be called.
  15077.    Some (such as 20H and 27H) have been replaced by DOS functions. Others are
  15078.    used internally by DOS.
  15079.  
  15080.    You can also access ROM-BIOS services through interrupt calls. See the
  15081.    on-line Help system for a description of all these services.
  15082.  
  15083.  
  15084.  15.4.1  Calling Interrupts
  15085.  
  15086.    Interrupts are called with the INT instruction.
  15087.  
  15088.    Syntax
  15089.  
  15090.    INT interruptnumber
  15091.    INTO
  15092.  
  15093.    The INT instruction takes an immediate operand with a value between 0 and
  15094.    255.
  15095.  
  15096.    When calling DOS and ROM-BIOS interrupts, a function number is usually
  15097.    placed in the AH register. Other registers may be used to pass arguments
  15098.    to functions. Some interrupts and functions return values in certain
  15099.    registers. Register use varies for each interrupt.
  15100.  
  15101.    When the instruction is called, the processor takes the following six
  15102.    steps:
  15103.  
  15104.    1. Looks up the address of the interrupt routine in the interrupt
  15105.       descriptor table. In real mode, this table starts at the lowest point
  15106.       in memory (segment 0, offset 0) and consists of four bytes (two segment
  15107.       and two offset) for each interrupt. Thus, the address of an interrupt
  15108.       routine can be found by multiplying the number of the interrupt by 4.
  15109.  
  15110.    2. Pushes the flags register, the current code segment (CS), and the
  15111.       current instruction pointer (IP).
  15112.  
  15113.    3. Clears the trap (TF) and interrupt enable (IF) flags.
  15114.  
  15115.    4. Jumps to the address of the interrupt routine, as specified in the
  15116.       interrupt description table.
  15117.  
  15118.    5. Executes the code of the interrupt routine until it encounters an IRET
  15119.       instruction.
  15120.  
  15121.    6. Pops the instruction pointer, code segment, and flags.
  15122.  
  15123.    Figure 15.3 illustrates how interrupts work.
  15124.  
  15125.    ┌────────────────────────────────────────────────────────────────────────┐
  15126.    │ This figure can be found in Section 15.4.1 of the manual               │
  15127.    └────────────────────────────────────────────────────────────────────────┘
  15128.  
  15129.    The INTO (Interrupt On Overflow) instruction is a variation of the INT
  15130.    instruction. It calls interrupt 04H if called when the overflow flag is
  15131.    set. By default, the routine for interrupt 4 simply consists of an IRET so
  15132.    that it returns without doing anything. However, you can write your own
  15133.    overflow interrupt routine. Using INTO is an alternative to using JO (Jump
  15134.    On Overflow) to jump to an overflow routine. Section 15.4.2, "Defining
  15135.    and Redefining Interrupt Routines," gives an example of this.
  15136.  
  15137.    The CLI (Clear Interrupt Flag) and STI (Set Interrupt Flag) instructions
  15138.    can be used to turn interrupts on or off. You can use CLI to turn
  15139.    interrupt processing off so that an important routine cannot be stopped by
  15140.    a hardware interrupt. After the routine has finished, use STI to turn
  15141.    interrupt processing back on. Interrupts received while interrupt
  15142.    processing was turned off by CLI are saved and executed when STI turns
  15143.    interrupts back on.
  15144.  
  15145.    Example 1
  15146.  
  15147.    ; DOS call (Display String)
  15148.  
  15149.                mov     ah,09h             ; Load function number
  15150.                mov     dx,OFFSET string   ; Load argument
  15151.                int     21h                ; Call DOS
  15152.  
  15153.    Example 2
  15154.  
  15155.    ; BIOS call (Read Character from Keyboard)
  15156.  
  15157.                xor     ah,ah              ; Load function number 0 in AH
  15158.                int     16h                ; Call BIOS
  15159.                                           ; Return scan code in AH
  15160.                                           ; Return ascii code in AL
  15161.  
  15162.    Example 1 is a call to a DOS function.
  15163.  
  15164.    Example 2 is a ROM-BIOS call that works on IBM Personal Computers and
  15165.    IBM-compatible computers. See the on-line Help system for complete
  15166.    information on DOS and BIOS calls.
  15167.  
  15168.  
  15169.  15.4.2  Defining and Redefining Interrupt Routines
  15170.  
  15171.    You can write your own interrupt routines, either to replace an existing
  15172.    routine or to use an undefined interrupt number.
  15173.  
  15174.    Syntax
  15175.  
  15176.    label PROC FAR[[USES reglist]]
  15177.    statements
  15178.    IRET
  15179.    label ENDP
  15180.  
  15181.    An interrupt routine can be written like a procedure by using the PROC and
  15182.    ENDP directives. The only differences are that the routine should always
  15183.    be defined as far and the routine should be terminated by an IRET
  15184.    instruction instead of a RET instruction.
  15185.  
  15186.    ──────────────────────────────────────────────────────────────────────────
  15187.    NOTE  Since the assembler doesn't know whether you are going to terminate
  15188.    with a RET or an IRET, it is possible to use the full extended PROC syntax
  15189.    (described in Section 15.3.4) for interrupt procedures. However, making
  15190.    interrupt procedures NEAR or specifying arguments for them makes no sense.
  15191.    The USES keyword does correctly generate code to save and restore a
  15192.    register list in interrupt procedures.
  15193.    ──────────────────────────────────────────────────────────────────────────
  15194.  
  15195.    Your program should replace the address in the interrupt descriptor table
  15196.    with the address of your routine. DOS calls are provided for this task.
  15197.    Another common technique is to jump to the old interrupt routine and let
  15198.    it do the IRET instruction.
  15199.  
  15200.    It is usually a good idea to save the old address and restore it before
  15201.    your program ends.
  15202.  
  15203.    Interrupt routines you may want to replace include the processor's
  15204.    divide-overflow (0H) and overflow (04H) interrupts. You can also replace
  15205.    DOS interrupts, such as the critical-error (24H) and CONTROL+C (23H)
  15206.    handlers. Interrupt routines can be part of device drivers. Writing
  15207.    interrupt routines is usually a systems task. The example below
  15208.    illustrates a simple routine. For complete information, see the Microsoft
  15209.    MS-DOS Programmer's Reference or one of the other reference books on DOS.
  15210.  
  15211.    Example
  15212.  
  15213.                .DATA
  15214.    message     DB      "Overflow - result set to 0",13,10,"$"
  15215.    vector      DD      ?
  15216.                .CODE
  15217.                .STARTUP
  15218.  
  15219.                mov     ax,3504h              ; Load interrupt 4 and call DOS
  15220.                int     21h                   ;   get interrupt vector function
  15221.                mov     WORD PTR vector[2],es ; Save segment
  15222.                mov     WORD PTR vector[0],bx ;   and offset
  15223.  
  15224.                push    ds                    ; Save DS
  15225.                mov     ax,cs                 ; Load segment of new routine
  15226.                mov     ds,ax
  15227.                mov     dx,OFFSET overflow    ; Load offset of new routine
  15228.                mov     ax,2504h              ; Load interrupt 4 and call DOS
  15229.                int     21h                   ;   set interrupt vector function
  15230.                pop     ds                    ; Restore
  15231.                .
  15232.                .
  15233.                .
  15234.                add     ax,bx                 ; Do addition (or multiplication)
  15235.                into                          ; Call interrupt 4 if overflow
  15236.                .
  15237.                .
  15238.                .
  15239.                lds     dx,vector             ; Load original interrupt address
  15240.                mov     ax,2504h              ; Restore interrupt number 4
  15241.                int     21h                   ;   with DOS set vector function
  15242.                mov     ax,4C00h              ; Terminate function
  15243.                int     21h
  15244.  
  15245.    overflow    PROC    FAR
  15246.                sti                           ; Enable interrupts
  15247.                                              ;   (turned off by INT)
  15248.                mov     ah,09h                ; Display string function
  15249.                mov     dx,OFFSET message     ; Load address
  15250.                int     21h                   ; Call DOS
  15251.                xor     ax,ax                 ; Set AX to 0
  15252.                xor     dx,dx                 ; Set DX to 0
  15253.                iret                          ; Return
  15254.    overflow    ENDP
  15255.                END     start
  15256.  
  15257.    In this example, DOS functions are used to save the address of the initial
  15258.    interrupt routine in a variable and to put the address of the new
  15259.    interrupt routine in the interrupt table. Once the new address has been
  15260.    set, the new routine is called any time the interrupt is called. The
  15261.    sample interrupt handler sets the result of a calculation that causes an
  15262.    overflow (either in AX or AX:DX) to 0. It is good practice to restore the
  15263.    original interrupt address before terminating the program.
  15264.  
  15265.  
  15266.  15.5  Checking Memory Ranges
  15267.  
  15268.    80186/286/386 Only
  15269.  
  15270.    Starting with the 80186 processor, the BOUND instruction can check to see
  15271.    if a value is within a specified range. This instruction is usually used
  15272.    to check a signed index value to see if it is within the range of an
  15273.    array. BOUND is a conditional interrupt instruction like INTO. If the
  15274.    condition is not met (the index is out of range), an interrupt 5 is
  15275.    executed.
  15276.  
  15277.    Syntax
  15278.  
  15279.    BOUND register16, memory32
  15280.  
  15281.    To use it for this purpose, the starting and ending values of the array mu
  15282.    st be stored as 16-bit values in the low and high words of a doubleword me
  15283.    mory operand. This operand is given as the source operand. The index value
  15284.     to be checked is given as the destination operand. If the index value is
  15285.    out of range, the instruction issues interrupt 5. This means that the oper
  15286.    ating system or the program must provide an interrupt routine for interrup
  15287.    t 5. DOS does not provide such a routine, so you must write your own. See
  15288.    Section 15.4, "Using Interrupts," for more information.
  15289.  
  15290.    Example
  15291.  
  15292.                .DATA
  15293.    bottom      EQU     0
  15294.    top         EQU     19
  15295.    dbounds     LABEL   DWORD              ; Allocate boundaries
  15296.    wbounds     DW      bottom,top         ;   initialized to bounds
  15297.    array       DB      top+1 DUP (?)      ; Allocate array
  15298.                .CODE
  15299.                .
  15300.                .
  15301.                .                          ; Assume index in DI
  15302.                bound   di,dbounds         ; Check to see if it is in range
  15303.                                           ;   if out of range, interrupt 5
  15304.                mov     dx,array[di]       ; If in range, use it
  15305.  
  15306.  
  15307.  
  15308.  ────────────────────────────────────────────────────────────────────────────
  15309.  Chapter 16:  Processing Strings
  15310.  
  15311.  
  15312.    The 8086-family processors have a full set of instructions for
  15313.    manipulating strings. In the discussion of these instructions, the term
  15314.    "string" refers not only to the common definition of a string──a sequence
  15315.    of bytes containing characters──but to any sequence of bytes or words
  15316.  
  15317.    The following instructions are provided for 8086-family string functions:
  15318.  
  15319.    Instruction         Description
  15320.    ──────────────────────────────────────────────────────────────────────────
  15321.    MOVS                Moves string from one location to another
  15322.  
  15323.    SCAS                Scans string for specified values
  15324.  
  15325.    CMPS                Compares values in one string with values in another
  15326.  
  15327.    LODS                Loads values from a string to accumulator register
  15328.  
  15329.    STOS                Stores values from accumulator register to a string
  15330.  
  15331.    INS                 Transfers values from a port to memory
  15332.  
  15333.    OUTS                Transfers values from memory to a port
  15334.  
  15335.  
  15336.    All these instructions use registers in the same way and have a similar
  15337.    syntax. Most are used with the repeat instruction prefixes: REP, REPE,
  15338.    REPNE, REPZ, and REPNZ.
  15339.  
  15340.    This chapter first explains the general format for string instructions and
  15341.    then tells you how to use each instruction.
  15342.  
  15343.  
  15344.  16.1  Setting Up String Operations
  15345.  
  15346.    The string instructions all work in a similar way. Once you understand the
  15347.    gen-eral procedure, it is easy to adapt the format for a particular string
  15348.    operation. The five steps are listed below:
  15349.  
  15350.    1. Make sure the direction flag indicates the direction in which you want
  15351.       the string to be processed. If the direction flag is clear, the string
  15352.       will be pro-cessed up (from low addresses to high addresses). If the
  15353.       direction flag is set, the string will be processed down (from high
  15354.       addresses to low addresses). The CLD instruction clears the flag, while
  15355.       STD sets it. Under DOS, the direction flag will normally be cleared if
  15356.       your program has not changed it.
  15357.  
  15358.    2. Load the number of iterations for the string instruction into the CX
  15359.       register. For instance, if you want to process a 100-byte string, load
  15360.       100. If a string instruction will be terminated conditionally, load the
  15361.       maximum number of iterations that can be done without an error.
  15362.  
  15363.    3. Load the starting offset address of the source string into DS:SI and
  15364.       the starting address of the destination string into ES:DI. Some string
  15365.       instructions take only a destination or source (shown in Table 16.1
  15366.       below). Normally, the segment address of the source string should be
  15367.       DS, but you can use a segment override with the string instruction to
  15368.       specify a different segment. You cannot override the segment address
  15369.       for the destination string. Therefore, you may need to change the value
  15370.       of ES.
  15371.  
  15372.    4. Choose the appropriate repeat-prefix instruction. Table 16.1 shows the
  15373.       repeat prefixes that can be used with each instruction.
  15374.  
  15375.    5. Put the appropriate string instruction immediately after the repeat
  15376.       prefix (on the same line).
  15377.  
  15378.    String instructions have two basic forms, as shown below:
  15379.  
  15380.    Syntax 1
  15381.  
  15382.    [[repeatprefix]] stringinstruction[[ES:[[destination,]]]]
  15383.    [[[[segmentregister:]]source]]
  15384.  
  15385.    The string instruction can be given with the source and/or destination as
  15386.    operands. The size of the operand or operands indicates the size of the
  15387.    objects to be processed by the string. Note that the operands only specify
  15388.    the size. The actual values to be worked on are the ones pointed to by
  15389.    DS:SI and/or ES:DI. No error is generated if the operand is not the same
  15390.    as the actual source or destination. One important advantage of this
  15391.    syntax is that the source operand can have a segment override. The
  15392.    destination operand is always relative to ES and cannot be overridden.
  15393.  
  15394.    Syntax 2
  15395.  
  15396.    [[repeatprefix]] stringinstructionB
  15397.    [[repeatprefix]] stringinstructionW
  15398.  
  15399.    The letter B or W appended to stringinstruction indicates bytes or words.
  15400.    With a letter appended to a string instruction, no operand is allowed.
  15401.  
  15402.    For instance, MOVS can be given with byte operands to move bytes or with
  15403.    word operands to move words. As an alternative, MOVSB can be given with no
  15404.    operands to move bytes, or MOVSW can be given with no operands to move
  15405.    words.
  15406.  
  15407.    Note that instructions that specify the size in the name never accept
  15408.    operands. Therefore, the following statement is illegal:
  15409.  
  15410.                lodsb     es:0               ; Illegal - no operand allowed
  15411.  
  15412.    Instead, the statement must be coded as shown below:
  15413.  
  15414.                lods      BYTE PTR es:0      ; Legal - use type specifier
  15415.  
  15416.    If a repeat prefix is used, it can be one of the following instructions:
  15417.  
  15418.    Instruction         Description
  15419.    ──────────────────────────────────────────────────────────────────────────
  15420.    REP                 Repeats for a specified number of iterations. The
  15421.                        number is given in CX.
  15422.  
  15423.    REPE or REPZ        Repeats while equal. The maximum number of iterations
  15424.                        should be specified in CX.
  15425.  
  15426.    REPNE or REPNZ      Repeats while not equal. The maximum number of
  15427.                        iterations should be specified in CX.
  15428.  
  15429.  
  15430.    REPE is the same as REPZ, and REPNE is the same as REPNZ. You can use
  15431.    whichever name you find more mnemonic. The prefixes ending with E are used
  15432.    in syntax listings and tables in the rest of this chapter.
  15433.  
  15434.    Table 16.1 lists each string instruction with the type of repeat prefix it
  15435.    uses and whether the instruction works on a source, a destination, or
  15436.    both.
  15437.  
  15438.    Table 16.1 Requirements for String Instructions
  15439.  
  15440.    Instruction   Repeat Prefix   Source/Destination  Register Pair
  15441.    ──────────────────────────────────────────────────────────────────────────
  15442.    MOVS          REP             Both                DS:SI, ES:DI
  15443.  
  15444.    SCAS          REPE/REPNE      Destination         ES:DI
  15445.  
  15446.    CMPS          REPE/REPNE      Both                ES:DI, DS:SI
  15447.  
  15448.    LODS          None            Source              DS:SI
  15449.  
  15450.    STOS          REP             Destination         ES:DI
  15451.  
  15452.    INS           REP             Destination         ES:DI
  15453.  
  15454.    OUTS          REP             Source              DS:SI
  15455.  
  15456.    ──────────────────────────────────────────────────────────────────────────
  15457.  
  15458.  
  15459.    At run time, a string instruction preceded by a repeat sequence causes the
  15460.    processor to take the following steps:
  15461.  
  15462.    1. Checks the CX registers and exits from the string instruction if CX is
  15463.       0.
  15464.  
  15465.    2. Performs the string operation once.
  15466.  
  15467.    3. Increases SI and/or DI if the direction flag is cleared. Decreases SI
  15468.       and/or DI if the direction flag is set. The amount of increase or
  15469.       decrease is 1 for byte operations, 2 for word operations.
  15470.  
  15471.    4. Decrements CX (no flags are modified).
  15472.  
  15473.    5. If the string instruction is SCAS or CMPS, checks the zero flag and
  15474.       exits if the repeat condition is false──that is, if the flag is set
  15475.       with REPE or REPZ or if it is clear with REPNE or REPNZ.
  15476.  
  15477.    6. Goes to the next iteration (step 1).
  15478.  
  15479.    Although string instructions (except LODS) are most often used with repeat
  15480.    prefixes, they can also be used by themselves. In this case, the SI and/or
  15481.    DI registers are adjusted as specified by the direction flag and the size
  15482.    of operands. However, you must decrement the CX register and set up a loop
  15483.    for the repeated action.
  15484.  
  15485.    ──────────────────────────────────────────────────────────────────────────
  15486.    NOTE  Although you can use a segment override on the source operand, a
  15487.    segment override combined with a repeat prefix can cause problems in
  15488.    certain situations. If an interrupt occurs during the string operation,
  15489.    the segment override is lost and the rest of the string operation
  15490.    processes incorrectly. Segment overrides can be used safely when
  15491.    interrupts are turned off.
  15492.    ──────────────────────────────────────────────────────────────────────────
  15493.  
  15494.  
  15495.  16.2  Moving Strings
  15496.  
  15497.    The MOVS instruction is used to move data from one area of memory to
  15498.    another.
  15499.  
  15500.    Syntax
  15501.  
  15502.    [[REP]] MOVS [[ES:]]destination,[[segmentregister:]]source
  15503.    [[REP]] MOVSB
  15504.    [[REP]] MOVSW
  15505.  
  15506.    To move the data, load the count and the source and destination addresses
  15507.    into the appropriate registers. Then use REP with the MOVS instruction.
  15508.  
  15509.    Example 1
  15510.  
  15511.                .MODEL  small
  15512.                .DATA
  15513.    source      DB      10 DUP ('0123456789')
  15514.    destin      DB      100 DUP (?)
  15515.                .CODE
  15516.                mov     ax,@data           ; Load same segment
  15517.                mov     ds,ax              ;   to both DS
  15518.                mov     es,ax              ;   and ES
  15519.                .
  15520.                .
  15521.                .
  15522.                cld                        ; Work upward
  15523.                mov     cx,100             ; Set iteration count to 100
  15524.                mov     si,OFFSET source   ; Load address of source
  15525.                mov     di,OFFSET destin   ; Load address of destination
  15526.                rep     movsb              ; Move 100 bytes
  15527.  
  15528.    Example 1 shows how to move a string by using string instructions. For
  15529.    comparison, Example 2 shows a much less efficient way of doing the same
  15530.    operation without string instructions.
  15531.  
  15532.    Example 2
  15533.  
  15534.                .MODEL  small
  15535.                .DATA
  15536.    source      DB      10 DUP ('0123456789')
  15537.    destin      DB      100 DUP (?)
  15538.                .CODE
  15539.                .                          ; Assume ES = DS
  15540.                .
  15541.                .
  15542.                mov     cx,100             ; Set iteration count to 100
  15543.                mov     si,OFFSET source   ; Load offset of source
  15544.                mov     di,OFFSET destin   ; Load offset of destination
  15545.    repeat:     mov     al,[si]            ; Get a byte from source
  15546.                mov     [di],al            ; Put it in destination
  15547.                inc     si                 ; Increment source pointer
  15548.                inc     di                 ; Increment destination pointer
  15549.                loop    repeat             ; Do it again
  15550.  
  15551.    Both examples illustrate how to move byte strings in a small-model program
  15552.    in which DS already points to the segment containing the variables. In
  15553.    such programs, ES can be set to the same value as DS.
  15554.  
  15555.    There are several variations on this. If the source string was not in the
  15556.    current data segment, you could load the starting address of its segment
  15557.    into ES. Another option would be to use the MOVS instruction with operands
  15558.    and give a segment override on the source operand. For example, you could
  15559.    use the following statement if ES pointed to both the source and the
  15560.    destination strings:
  15561.  
  15562.                rep     movs destin,es:source
  15563.  
  15564.    It is sometimes faster to move a string of bytes as words. You must adjust
  15565.    for any odd bytes, as shown in Example 3. Assume the source and
  15566.    destination are already loaded.
  15567.  
  15568.    Example 3
  15569.  
  15570.                mov     cx,count           ; Load count
  15571.                shr     cx,1               ; Divide by 2 (carry will be set
  15572.                                           ;   if count is odd)
  15573.                rep     movsw              ; Move words
  15574.                rcl     cx,1               ; If odd, make CX 1
  15575.                rep     movsb              ; Move odd byte if there is one
  15576.  
  15577.  
  15578.  16.3  Searching Strings
  15579.  
  15580.    The SCAS instruction is used to scan a string for a specified value.
  15581.  
  15582.    Syntax
  15583.  
  15584.    [[REPE | REPNE]] SCAS [[ES:]]destination
  15585.    [[REPE | REPNE]] SCASB
  15586.    [[REPE | REPNE]] SCASW
  15587.  
  15588.    SCAS and its variations work only on a destination string, which must be
  15589.    pointed to by ES:DI. The value to scan for must be in the accumulator
  15590.    register──AL for bytes, AX for words.
  15591.  
  15592.    The SCAS instruction works by comparing the value pointed to by DI with
  15593.    the value in the accumulator. If the values are the same, the zero flag is
  15594.    set. Thus, the instruction only makes sense when used with one of the
  15595.    repeat prefixes that checks the zero flag.
  15596.  
  15597.    If you want to search for the first occurrence of a specified value, use
  15598.    the REPNE or REPNZ instruction. If the value is found, ES:DI will point to
  15599.    the value immediately after the first occurrence. You can decrement DI to
  15600.    make it point to the first matching value.
  15601.  
  15602.    If you want to search for the first value that does not have a specified
  15603.    value, use REPE or REPZ. If the value is found, ES:DI will point to the
  15604.    position after the first nonmatching value. You can decrement DI to make
  15605.    it point to the first non-matching value.
  15606.  
  15607.    After a REPNE SCAS, the zero flag will be cleared if no match was found.
  15608.    After a REPE SCAS, the zero flag will be set if no nonmatch was found.
  15609.  
  15610.    Example
  15611.  
  15612.               .DATA
  15613.    string      DB      "The quick brown fox jumps over the lazy dog"
  15614.    lstring     EQU     $-string           ; Length of string
  15615.    pstring     DD      string             ; Far pointer to string
  15616.                .CODE
  15617.                .
  15618.                .
  15619.                .
  15620.                cld                        ; Work upward
  15621.                mov     cx,lstring         ; Load length of string
  15622.                les     di,pstring         ; Load address of string
  15623.                mov     al,'z'             ; Load character to find
  15624.                repne   scasb              ; Search
  15625.                jnz     notfound           ; CX is 0 if not found
  15626.                .                          ; ES:DI points to character
  15627.                .                          ;   after first 'z'
  15628.                .
  15629.    notfound:                              ; Special case for not found
  15630.  
  15631.    This example assumes that ES is not the same as DS, but that the address
  15632.    of the string is stored in a pointer variable. The LES instruction is used
  15633.    to load the far address of the string into ES:DI.
  15634.  
  15635.  
  15636.  16.4  Comparing Strings
  15637.  
  15638.    The CMPS instruction is used to compare two strings and point to the
  15639.    address where a match or nonmatch occurs.
  15640.  
  15641.    Syntax
  15642.  
  15643.    [[REPE | REPNE]] CMPS [[segmentregister:]]source,[[ES:]],destination
  15644.    [[REPE | REPNE]] CMPSB
  15645.    [[REPE | REPNE]] CMPSW
  15646.  
  15647.    The count and the addresses of the strings are loaded into registers, as
  15648.    described in Section 16.1, "Setting Up String Operations." Either string
  15649.    can be considered the destination or source string unless a segment
  15650.    override is used. Notice that unlike other instructions, CMPS requires
  15651.    that the source be on the left.
  15652.  
  15653.    The CMPS instruction works by comparing, in turn, each value pointed to by
  15654.    DI with the value pointed to by SI. If the values are the same, the zero
  15655.    flag is set. Thus, the instruction makes sense only when used with one of
  15656.    the repeat prefixes that checks the zero flag.
  15657.  
  15658.    If you want to search for the first match between the strings, use the
  15659.    REPNE or REPNZ instruction. If a match is found, ES:DI and DS:SI will
  15660.    point to the position after the first match in the respective strings. You
  15661.    can decrement DI or SI to point to the match. (Conversely, you would
  15662.    increment DI or SI if the direction flag was set.)
  15663.  
  15664.    If you want to search for a nonmatch, use REPE or REPZ. If a nonmatch is
  15665.    found, ES:DI and DS:SI will point to the position after the first nonmatch
  15666.    in the respective strings. You can decrement DI or SI to point to the
  15667.    nonmatch.
  15668.  
  15669.    After a REPNE CMPS, the zero flag will be cleared if no match was found.
  15670.    After a REPE CMPS, the zero flag will be set if no nonmatch was found.
  15671.  
  15672.    Example
  15673.  
  15674.                .MODEL  large
  15675.                .DATA
  15676.    string1     DB      "The quick brown fox jumps over the lazy dog"
  15677.                .FARDATA
  15678.    string2     DB      "The quick brown dog jumps over the lazy fox"
  15679.    lstring     EQU     $-string2
  15680.                .CODE
  15681.                mov     ax,@data           ; Load data segment
  15682.                mov     ds,ax              ;   into DS
  15683.                mov     ax,@fardata        ; Load far data segment
  15684.                mov     es,ax              ;   into ES
  15685.                .
  15686.                .
  15687.                .
  15688.                cld                        ; Work upward
  15689.                mov     cx,lstring         ; Load length of string
  15690.                mov     si,OFFSET string1  ; Load offset of string1
  15691.                mov     di,OFFSET string2  ; Load offset of string2
  15692.                repe    cmpsb              ; Compare
  15693.                jnz     allmatch           ; CX is 0 if no nonmatch
  15694.                dec     si                 ; Adjust to point to nonmatch
  15695.                dec     di                 ;   in each string
  15696.                .
  15697.                .
  15698.    allmatch:   .                          ; Special case for all match
  15699.  
  15700.    This example assumes that the strings are in different segments. Both
  15701.    segments must be initialized to the appropriate segment register.
  15702.  
  15703.  
  15704.  16.5  Filling Strings
  15705.  
  15706.    The STOS instruction is used to store a specified value in each position
  15707.    of a string.
  15708.  
  15709.    Syntax
  15710.  
  15711.    [[REP]] STOS [[ES:]]destination
  15712.    [[REP]] STOSB
  15713.    [[REP]] STOSW
  15714.  
  15715.    The string is considered the destination, so it must be pointed to by
  15716.    ES:DI. The length and address of the string must be loaded into registers,
  15717.    as described in Section 16.1, "Setting Up String Operations." The value
  15718.    to store must be in the accumulator register──AL for bytes, AX for words.
  15719.  
  15720.    For each iteration specified by the REP instruction prefix, the value in
  15721.    the accumulator is loaded into the string.
  15722.  
  15723.    Example
  15724.  
  15725.                .MODEL  small
  15726.                .DATA
  15727.    destin      DB      100 DUP ?
  15728.                .CODE
  15729.                .                          ; Assume ES = DS
  15730.                .
  15731.                .
  15732.                cld                        ; Work upward
  15733.                mov     ax,'aa'            ; Load character to fill
  15734.                mov     cx,50              ; Load length of string
  15735.                mov     di,OFFSET destin   ; Load address of destination
  15736.                rep     stosw              ; Store 'a' into array
  15737.  
  15738.    This example loads 100 bytes containing the character 'a'. Notice that
  15739.    this is done by storing 50 words rather than 100 bytes. This makes the
  15740.    code faster by reducing the number of iterations. You would have to adjust
  15741.    for the last byte if you wanted to fill an odd number of bytes.
  15742.  
  15743.  
  15744.  16.6  Loading Values from Strings
  15745.  
  15746.    The LODS instruction is used to load a value from a string into a
  15747.    register.
  15748.  
  15749.    Syntax
  15750.  
  15751.    LODS [[segmentregister:]]source
  15752.    LODSB
  15753.    LODSW
  15754.  
  15755.    The string is considered the source, so it must be pointed to by DS:SI.
  15756.    The value is always loaded from the string into the accumulator
  15757.    register──AL for bytes, AX for words.
  15758.  
  15759.    Unlike other string instructions, LODS is not normally used with a repeat
  15760.    prefix since there is no reason to move a value repeatedly to a register.
  15761.    However, LODS does adjust the SI register as specified by the direction
  15762.    flag and the size of operands. The programmer must code the instructions
  15763.    to use the value after it is loaded.
  15764.  
  15765.    Example 1
  15766.  
  15767.                .DATA
  15768.    stuff       DB      0,1,2,3,4,5,6,7,8,9
  15769.                .CODE
  15770.                .
  15771.                .
  15772.                .
  15773.                cld                          ; Work upward
  15774.                mov     cx,10                ; Load length
  15775.                mov     si,OFFSET stuff      ; Load offset of source
  15776.                mov     ah,2                 ; Display character function
  15777.    get:        lodsb                        ; Get a character
  15778.                add     al,'0'               ; Convert to ASCII
  15779.                mov     dl,al                ; Move to DL
  15780.                int     21h                  ; Call DOS to display character
  15781.                loop    get                  ; Repeat
  15782.  
  15783.    Example 1 loads, processes, and displays each byte in a string of bytes.
  15784.  
  15785.    Example 2
  15786.  
  15787.                .DATA
  15788.    buffer      DB      80 DUP(?)            ; Create buffer for argument strin
  15789.                .CODE
  15790.    start:      mov     ax,@data             ; Initialize DS
  15791.                mov     ds,ax
  15792.                                             ; On start-up ES points to PSP
  15793.                cld                          ; Work upward
  15794.                mov     cl,BYTE PTR es:[80h] ; Load length of arguments
  15795.                xor     ch,ch
  15796.                mov     di,OFFSET buffer     ; Load offset of buffer
  15797.                mov     si,82h               ; Load position of argument string
  15798.                mov     dx,es                ; Exchange ES and DS
  15799.                mov     ax,ds
  15800.                mov     es,ax
  15801.                mov     ds,dx
  15802.    another:    lodsb                        ; Get a character
  15803.                cmp     al,'a'               ; Is it high enough to be upper?
  15804.                jb      noway                ; No? Check
  15805.                cmp     al,'z'               ; Is it low enough to be letter?
  15806.                ja      noway
  15807.                sub     al,32                ; Yes? Convert to uppercase
  15808.  
  15809.    noway:      stosb
  15810.                loop    another              ; Repeat
  15811.                mov     dx,es                ; Restore ES and DS
  15812.                mov     ax,ds
  15813.                mov     es,ax
  15814.                mov     ds,dx
  15815.  
  15816.    Example 2 copies the command arguments from position 82H in the DOS
  15817.    Program Segment Prefix (PSP) while converting them to uppercase. See the
  15818.    Microsoft MS-DOS Programmer's Reference or one of the many other books on
  15819.    DOS for information about the PSP. Notice that both LODSB and STOSB are
  15820.    used without repeat prefixes.
  15821.  
  15822.  
  15823.  16.7  Transferring Strings to and from Ports
  15824.  
  15825.    80186/286/386 Only
  15826.  
  15827.    The INS instruction reads a string from a port to memory, and the OUTS
  15828.    instruction writes a string from memory to a port.
  15829.  
  15830.    Syntax
  15831.  
  15832.    OUTS DX,[[segmentregister:]]source
  15833.    OUTSB
  15834.    OUTSW
  15835.  
  15836.    INS [[ES:]]destination,DX
  15837.    INSB
  15838.    INSW
  15839.  
  15840.    The INS and OUTS instructions require that the number of the port be in
  15841.    DX. The port cannot be specified as an immediate value, as it can be with
  15842.    IN and OUT.
  15843.  
  15844.    To move the data, load the count into CX. The string to be transferred by
  15845.    INS is considered the destination string, so it must be pointed to by
  15846.    ES:DI. The string to be transferred by OUTS is considered the source
  15847.    string, so it must be pointed to by DS:SI.
  15848.  
  15849.    If you specify the source or destination as an operand, DX must be
  15850.    specified. Otherwise, DX is assumed and should be omitted.
  15851.  
  15852.    If you need to process the string as it is transferred (for instance, to
  15853.    check for the end of a null-terminated string), you must set up the loop
  15854.    yourself instead of using the REP instruction prefix.
  15855.  
  15856.    Example
  15857.  
  15858.                .DATA
  15859.    count       EQU     100
  15860.    buffer      DB      count DUP (?)
  15861.    inport      DW      ?
  15862.                .CODE
  15863.                .                          ; Assume ES = DS
  15864.                .
  15865.                .
  15866.                cld                        ; Work upward
  15867.                mov     cx,count           ; Load length to transfer
  15868.                mov     di,OFFSET buffer   ; Load address of destination
  15869.                mov     dx,inport          ; Load port number
  15870.                rep     insb               ; Transfer the string
  15871.                                           ;   from port to buffer
  15872.  
  15873.  
  15874.  
  15875.  ────────────────────────────────────────────────────────────────────────────
  15876.  Chapter 17:  Calculating with a Math Coprocessor
  15877.  
  15878.  
  15879.    The 8087-family coprocessors are used to do fast mathematical
  15880.    calculations. When used with real numbers, packed binary coded decimal
  15881.    (BCD) numbers, or long integers, they do calculations many times faster
  15882.    than the same operations done with 8086-family processors.
  15883.  
  15884.    This chapter explains how to use the 8087-family processors to transfer
  15885.    and process data. The approach taken is from an applications standpoint.
  15886.    Features that would be used by systems programmers (such the flags used
  15887.    when writing exception handlers) are not explained. This chapter is
  15888.    intended as a reference, not a tutorial.
  15889.  
  15890.    ──────────────────────────────────────────────────────────────────────────
  15891.    NOTE  This manual does not attempt to explain the mathematical concepts
  15892.    involved in using certain coprocessor features. It assumes that you will
  15893.    not need to use a feature unless you understand the mathematics involved.
  15894.    For example, you need to understand logarithms to use the FYL2X and
  15895.    FYL2XP1 instructions.
  15896.    ──────────────────────────────────────────────────────────────────────────
  15897.  
  15898.  
  15899.  17.1  Coprocessor Architecture
  15900.  
  15901.    The math coprocessor works simultaneously with the main processor.
  15902.    However, since the coprocessor cannot handle device input or output, most
  15903.    data originates in the main processor.
  15904.  
  15905.    The main processor and the coprocessor have their own registers, which are
  15906.    completely separate and inaccessible to the other. They exchange data
  15907.    through memory, since memory is available to both.
  15908.  
  15909.    Ordinarily you follow these three steps when using the coprocessor:
  15910.  
  15911.    1. Load data from memory to coprocessor registers.
  15912.  
  15913.    2. Process the data.
  15914.  
  15915.    3. Store the data from coprocessor registers back to memory.
  15916.  
  15917.    Step 2, processing the data, can occur while the main processor is
  15918.    handling other tasks. Steps 1 and 3 must be coordinated with the main
  15919.    processor so that the processor and coprocessor do not try to access the
  15920.    same memory at the same time, as explained in Section 17.5, "Transferring
  15921.    Data."
  15922.  
  15923.  
  15924.  17.1.1  Coprocessor Data Registers
  15925.  
  15926.    The 8087-family coprocessors have eight 80-bit data registers. Unlike
  15927.    8086-family registers, the coprocessor data registers are organized as a
  15928.    stack. As data is pushed into the top register, previous data items move
  15929.    into higher-numbered registers. Register 0 is the top of the stack;
  15930.    register 7 is the bottom. The syntax for specifying registers is shown
  15931.    below:
  15932.  
  15933.    ST[[(number)]]
  15934.  
  15935.    The number must be a digit between 0 and 7, or a constant expression that
  15936.    evaluates to a number from 0 to 7. If number is omitted, register 0 (top
  15937.    of stack) is assumed.
  15938.  
  15939.    All coprocessor data is stored in registers in the temporary-real format.
  15940.    This is the 10-byte IEEE format described in Section 6.5.1.4,
  15941.    "Real-Number Variables." The registers and the register format are shown
  15942.    in Figure 17.1.
  15943.  
  15944.    ┌────────────────────────────────────────────────────────────────────────┐
  15945.    │ This figure can be found in Section 17.1.1 of the manual               │
  15946.    └────────────────────────────────────────────────────────────────────────┘
  15947.  
  15948.    Internally, all calculations are done on numbers of the same type. Since
  15949.    temporary-real numbers have the greatest precision, lower-precision
  15950.    numbers are guaranteed not to lose precision as a result of calculations.
  15951.    The instructions that transfer values between the main processor and the
  15952.    coprocessor automatically convert numbers to and from the temporary-real
  15953.    format.
  15954.  
  15955.  
  15956.  17.1.2  Coprocessor Control Registers
  15957.  
  15958.    The 8087-family coprocessors have seven 16-bit control registers. The most
  15959.    useful control registers are made up of bit fields or flags. Some flags
  15960.    control coprocessor operations, while others maintain the current status
  15961.    of the coprocessor. In this sense, they are much like the 8086-family
  15962.    flags registers.
  15963.  
  15964.    You do not need to understand these registers to do most coprocessor
  15965.    operations. Control flags are set by default to the values appropriate for
  15966.    most programs. Errors and exceptions are reported in the status-word
  15967.    register. However, the coprocessor already has a default system for
  15968.    handling exceptions. Applications programmers can usually accept the
  15969.    defaults. Systems programmers may want to use the status-word and
  15970.    control-word registers when writing exception handlers, but such problems
  15971.    are beyond the scope of this manual.
  15972.  
  15973.    Figure 17.2 shows the overall layout of the control registers, including
  15974.    the control word, status word, tag word, instruction pointer, and operand
  15975.    pointer. The format of each of the registers is not shown, since these
  15976.    registers are generally of use only to systems programmers. The exception
  15977.    is the condition-code bits of the status-word register. These bits are
  15978.    explained in Section 17.7, "Controlling Program Flow."
  15979.  
  15980.    ┌────────────────────────────────────────────────────────────────────────┐
  15981.    │ This figure can be found in Section 17.1.2 of the manual               │
  15982.    └────────────────────────────────────────────────────────────────────────┘
  15983.  
  15984.    The control registers are explained in more detail in the on-line Help
  15985.    system.
  15986.  
  15987.  
  15988.  17.2  Emulation
  15989.  
  15990.    You can write assembly-language procedures that use the emulator library
  15991.    when called from QuickC. First write the procedure by using coprocessor
  15992.    instructions, then assemble it using the /E option, and finally link it
  15993.    with your high-level-language modules. When compiling modules, use the
  15994.    compiler options that specify emulation.
  15995.  
  15996.    Some coprocessor instructions are not emulated by Microsoft emulation
  15997.    libraries. Which instructions are emulated varies depending on the
  15998.    language and version. If you use a coprocessor instruction that is not
  15999.    emulated, the program will generate a run-time error when it tries to
  16000.    execute the unemulated instruction. You cannot use a Microsoft emulation
  16001.    library with stand-alone assembler programs, since the library depends on
  16002.    the compiler start-up code.
  16003.  
  16004.    See Appendix B, Section B.6, "Creating Code for a Floating-Point
  16005.    Emulator," for information on the /E option. See Appendix A,
  16006.    "Mixed-Language Mechanics," for information on writing assembly-language
  16007.    procedures for high-level languages.
  16008.  
  16009.  
  16010.  17.3  Using Coprocessor Instructions
  16011.  
  16012.    Coprocessor instructions are readily recognizable because, unlike all
  16013.    8086-family instruction mnemonics, they start with the letter F.
  16014.  
  16015.    Most coprocessor instructions have two operands, but in many cases, one or
  16016.    both operands are implied. Often, one operand can be a memory operand; in
  16017.    this case, the other operand is always implied as the stack-top register.
  16018.    Coprocessor instructions can never have immediate operands, and with the
  16019.    exception of the FSTSW instruction (see Section 17.5.2, "Loading
  16020.    Constants"), they cannot have processor registers as operands. As with
  16021.    8086-family instructions, memory-to-memory operations are never allowed.
  16022.    One operand must be a coprocessor register.
  16023.  
  16024.    Instructions usually have a source and a destination operand. The source
  16025.    specifies one of the values to be processed. It is never changed by the
  16026.    operation. The destination specifies the value to be operated on and
  16027.    replaced with the result of the operation. If two operands are specified,
  16028.    the first is the destination and the second is the source.
  16029.  
  16030.    The stack organization of registers gives the programmer flexibility to
  16031.    think of registers either as elements on a stack or as registers much like
  16032.    8086-family registers. Table 17.1 lists the variations of coprocessor
  16033.    instructions along with the syntax for each.
  16034.  
  16035.    Table 17.1 Coprocessor Operand Forms
  16036.  
  16037.    Instruction Form  Implied Syntax    Operands      Example
  16038.    ──────────────────────────────────────────────────────────────────────────
  16039.    Classical-stack   Faction           ST(1), ST     fadd
  16040.  
  16041.    Memory            Faction memory    ST            fadd memloc
  16042.  
  16043.    Register          Faction ST(num),  fadd st(5),st Faction ST, ST(num)
  16044.                      ST                              fadd st,st(3)
  16045.  
  16046.    Register pop      FactionP ST(num),               faddp st(4),st
  16047.                      ST
  16048.    ──────────────────────────────────────────────────────────────────────────
  16049.  
  16050.  
  16051.    Not all instructions accept all operand variations. For example, load and
  16052.    store instructions always require the memory form. Load-constant
  16053.    instructions always take the classical-stack form. Arithmetic instructions
  16054.    can usually take any form.
  16055.  
  16056.    Some instructions that accept the memory form can have the letter I
  16057.    (integer) or B (BCD) following the initial F to specify how a memory
  16058.    operand is to be interpreted. For example, FILD interprets its operand as
  16059.    an integer and FBLD interprets its operand as a BCD number. If no type
  16060.    letter is included in the instruction name, the instruction works on real
  16061.    numbers.
  16062.  
  16063.  
  16064.  17.3.1  Using Implied Operands in the Classical-Stack Form
  16065.  
  16066.    The classical-stack form treats coprocessor registers like items on a
  16067.    stack. Items are pushed onto or popped off the top elements of the stack.
  16068.    Since only the top item can be accessed on a traditional stack, there is
  16069.    no need to specify operands. The first register (and the second if there
  16070.    are two operands) is always assumed.
  16071.  
  16072.    In arithmetic operations (see Section 17.6), the top of the stack (ST) is
  16073.    the source operand, and the second register (ST(1)) is the destination.
  16074.    The result of the operation goes into the destination operand, and the
  16075.    source is popped off the stack. The effect is that both of the values used
  16076.    in the operation are destroyed and the result is left at the top of the
  16077.    stack.
  16078.  
  16079.    Instructions that load constants always use the stack form (see Section
  16080.    17.5.1, "Transferring Data to and from Registers"). In this case, the
  16081.    constant created by the instruction is the implied source, and the top of
  16082.    the stack (ST) is the destination. The source is pushed into the
  16083.    destination.
  16084.  
  16085.    Note that the classical-stack form with its implied operands is similar to
  16086.    the register-pop form, not to the register form. For example, fadd, with
  16087.    the implied operands ST(1),ST, is equivalent to faddp st(1),st, rather
  16088.    than to fadd st(1),st.
  16089.  
  16090.    Example
  16091.  
  16092.                fld1               ; Push 1 into first position
  16093.                fldpi              ; Push pi into first position
  16094.                fadd               ; Add pi and 1 and pop
  16095.  
  16096.    The status of the register stack after each instruction is shown below:
  16097.  
  16098.    ┌────────────────────────────────────────────────────────────────────────┐
  16099.    │ This figure can be found in Section 17.3.1 of the manual               │
  16100.    └────────────────────────────────────────────────────────────────────────┘
  16101.  
  16102.  
  16103.  17.3.2  Using Memory Operands
  16104.  
  16105.    The memory form treats coprocessor registers like items on a stack. Items
  16106.    are pushed from memory onto the top element of the stack, or popped from
  16107.    the top element to memory. Since only the top item can be accessed on a
  16108.    traditional stack, there is no need to specify the stack operand. The top
  16109.    register (ST) is always assumed. However, the memory operand must be
  16110.    specified.
  16111.  
  16112.    Memory operands can be used in load and store instructions (see Section
  16113.    17.5.1, "Transferring Data to and from Registers"). Load instructions
  16114.    push source values from memory to an implied destination register (ST).
  16115.    Store instructions pop source values from an implied source register (ST)
  16116.    to the destination in memory. Some versions of store instructions pop the
  16117.    register stack so that the source is destroyed. Others simply copy the
  16118.    source without changing the stack.
  16119.  
  16120.    Memory operands can also be used in calculation instructions that operate
  16121.    on two values (see Section 17.6, "Doing Arithmetic Calculations"). The
  16122.    memory operand is always the source. The stack top (ST) is always the
  16123.    implied destination. The result of the operation replaces the destination
  16124.    without changing its stack position.
  16125.  
  16126.    Example
  16127.  
  16128.                .DATA
  16129.    m1          DD      1.0
  16130.    m2          DD      2.0
  16131.                .CODE
  16132.                .
  16133.                .
  16134.                .
  16135.                fld     m1         ; Push m1 into first position
  16136.                fld     m2         ; Push m2 into first position
  16137.                fadd    m1         ; Add m2 to first position
  16138.                fstp    m1         ; Pop first position into m1
  16139.                fst     m2         ; Copy first position to m2
  16140.  
  16141.    The status of the register stack and the memory locations used in the
  16142.    instructions is shown below:
  16143.  
  16144.    ┌────────────────────────────────────────────────────────────────────────┐
  16145.    │ This figure can be found in Section 17.3.2 of the manual               │
  16146.    └────────────────────────────────────────────────────────────────────────┘
  16147.  
  16148.  
  16149.  17.3.3  Specifying Operands in the Register Form
  16150.  
  16151.    The register form treats coprocessor registers as traditional registers.
  16152.    Registers are specified the same as 8086-family instructions with two
  16153.    register operands. The only limitation is that one of the two registers
  16154.    must be the stack top (ST).
  16155.  
  16156.    In the register form, operands are specified by name. The second operand
  16157.    is the source; it is not affected by the operation. The first operand is
  16158.    the destination; its value is replaced with the result of the operation.
  16159.    The stack position of the operands does not change.
  16160.  
  16161.    The register form can only be used with the FXCH instruction and with
  16162.    arithmetic instructions that do calculations on two values. With the FXCH
  16163.    instruction, the stack top is implied and need not be specified.
  16164.  
  16165.    Example
  16166.  
  16167.                fadd    st(1),st   ; Add second position to first -
  16168.                                   ;   result goes in second position
  16169.                fadd    st,st(2)   ; Add first position to second -
  16170.                                   ;   result goes in first position
  16171.                fxch    st(1)      ; Exchange first and second positions
  16172.  
  16173.    The status of the register stack if the registers were previously
  16174.    initialized to 1.0, 2.0, and 3.0 is shown below:
  16175.  
  16176.    ┌────────────────────────────────────────────────────────────────────────┐
  16177.    │ This figure can be found in Section 17.3.3 of the manual               │
  16178.    └────────────────────────────────────────────────────────────────────────┘
  16179.  
  16180.  
  16181.  17.3.4  Specifying Operands in the Register-Pop Form
  16182.  
  16183.    The register-pop form treats coprocessor registers as a modified stack.
  16184.    This form has some of the aspects of both a stack and registers. The
  16185.    destination register can be specified by name, but the source register
  16186.    must always be the stack top.
  16187.  
  16188.    The result of the operation will be placed in the destination operand, and
  16189.    the stack top will be popped off the stack. The effect is that both values
  16190.    being operated on will be destroyed and the result of the operation will
  16191.    be saved in the specified destination register. The register-pop form is
  16192.    only used for instructions that do calculations on two values.
  16193.  
  16194.    Example
  16195.  
  16196.                faddp   st(2),st   ; Add first and third positions and pop -
  16197.                                   ;   first position destroyed
  16198.                                   ;   third moves to second and holds result
  16199.  
  16200.    The status of the register stack if the registers were already initialized
  16201.    to 1.0, 2.0, and 3.0 is shown below:
  16202.  
  16203.    ┌────────────────────────────────────────────────────────────────────────┐
  16204.    │ This figure can be found in Section 17.3.4 of the manual               │
  16205.    └────────────────────────────────────────────────────────────────────────┘
  16206.  
  16207.  
  16208.  17.4  Coordinating Memory Access
  16209.  
  16210.    Problems of coordinating memory access can occur when the coprocessor and
  16211.    the main processor both try to access a memory location at the same time.
  16212.    Since the processor and coprocessor work independently, they may not
  16213.    finish working on memory in the order in which you give instructions.
  16214.    There are two separate cases, and they are handled in different ways.
  16215.  
  16216.    In the first case, if a processor instruction is given and then followed
  16217.    by a coprocessor instruction, the coprocessor must wait until the
  16218.    processor is finished before it can start the next instruction. This is
  16219.    handled automatically by Quick-Assembler for the 8088 and 8086 or by the
  16220.    processor for the 80186 and 80286.
  16221.  
  16222.    ──────────────────────────────────────────────────────────────────────────
  16223.    Coprocessor Differences  To synchronize operations between the 8088 or
  16224.    8086 processor and the 8087 coprocessor, each 8087 instruction must be
  16225.    preceded by a WAIT instruction. This is not necessary for the 80287. If
  16226.    you use the .8087 directive, QuickAssembler inserts WAIT instructions
  16227.    automatically. However, if you use the .286 directive, QuickAssembler
  16228.    assumes the instructions are for the 80287 or 80387 and does not insert
  16229.    the WAIT instructions. If your code will never need to run on an 8086 or
  16230.    8088 processor, you can make your programs shorter and more efficient by
  16231.    using the .286 directive.
  16232.    ──────────────────────────────────────────────────────────────────────────
  16233.  
  16234.    In the second case, if a coprocessor instruction that accesses memory is
  16235.    followed by a processor instruction attempting to access the same memory
  16236.    location, memory access is not automatically synchronized. For instance,
  16237.    if you store a coprocessor register to a variable and then try to load
  16238.    that variable into a processor register, the coprocessor may not be
  16239.    finished. Thus, the processor gets the value that was in memory before the
  16240.    coprocessor finished, rather than the value stored by the coprocessor. Use
  16241.    the WAIT or FWAIT instruction (they are mnemonics for the same
  16242.    instruction) to ensure that the coprocessor finishes before the processor
  16243.    begins.
  16244.  
  16245.    Example
  16246.  
  16247.    ; Coprocessor instruction first - Wait needed
  16248.  
  16249.                fist    mem32                ; Store to memory
  16250.                fwait                        ; Wait until coprocessor is done
  16251.                mov     ax,WORD PTR mem32    ; Move to register
  16252.                mov     dx,WORD PTR mem32[2]
  16253.  
  16254.    ; Processor instruction first - No wait needed
  16255.  
  16256.                mov     WORD PTR mem32,ax    ; Load memory
  16257.                mov     WORD PTR mem32[2],dx
  16258.                fild    mem32                ; Load to register
  16259.  
  16260.  
  16261.  17.5  Transferring Data
  16262.  
  16263.    The 8087-family coprocessors have separate instructions for each of the
  16264.    following types of transfers:
  16265.  
  16266.    1. Transferring data between memory and registers, or between different
  16267.       registers
  16268.  
  16269.    2. Loading certain common constants into registers
  16270.  
  16271.    3. Transferring control data to and from memory
  16272.  
  16273.  
  16274.  17.5.1  Transferring Data to and from Registers
  16275.  
  16276.    Data-transfer instructions transfer data between main memory and the
  16277.    coprocessor registers, or between different coprocessor registers. Two
  16278.    basic principles govern data transfers:
  16279.  
  16280.    ■  The instruction determines whether a value in memory will be considered
  16281.       an integer, a BCD number, or a real number. The value is always
  16282.       considered a temporary-real number once it is transferred to the
  16283.       coprocessor.
  16284.  
  16285.    ■  The size of the operand determines the size of a value in memory.
  16286.       Values in the coprocessor always take up 10 bytes.
  16287.  
  16288.    The adjustments between formats are made automatically. Notice that
  16289.    floating-point numbers must be stored in the IEEE format, not in the
  16290.    Microsoft Binary format. Data is automatically stored correctly by
  16291.    default. It is stored incorrectly and the coprocessor instructions
  16292.    disabled if you use the .MSFLOAT directive. Data formats for real numbers
  16293.    are explained in Section 6.5.1.4, "Real-Number Variables."
  16294.  
  16295.    Data is transferred to stack registers by using load commands. These
  16296.    commands push data onto the stack from memory or coprocessor registers.
  16297.    Data is removed by using store commands. Some store commands pop data off
  16298.    the register stack into memory or coprocessor registers, whereas others
  16299.    simply copy the data without changing it on the stack.
  16300.  
  16301.  
  16302.  17.5.1.1  Real Transfers
  16303.  
  16304.    The following instructions are available for transferring real numbers:
  16305.  
  16306.    Syntax              Description
  16307.    ──────────────────────────────────────────────────────────────────────────
  16308.    FLD mem             Pushes a copy of mem into ST. The source must be a 4-,
  16309.                        8-, or 10-byte memory operand. It is automatically
  16310.                        converted to the temporary-real format.
  16311.  
  16312.    FLD ST(num)         Pushes a copy of the specified register into ST.
  16313.  
  16314.    FST mem             Copies ST to mem without affecting the register stack.
  16315.                        The destination can be a 4- or 8-byte memory operand.
  16316.                        It is automatically converted from temporary-real
  16317.                        format to short real or long real format, depending on
  16318.                        the size of the operand. It cannot be stored in the
  16319.                        10-byte-real format.
  16320.  
  16321.    FST ST(num)         Copies ST to the specified register. The current value
  16322.                        of the specified register is replaced.
  16323.  
  16324.    FSTP mem            Pops a copy of ST into mem. The destination can be a
  16325.                        4-, 8-, or 10-byte memory operand. It is automatically
  16326.                        converted from temporary-real format to the
  16327.                        appropriate real-number format, depending on the size
  16328.                        of the operand.
  16329.  
  16330.    FSTP ST(num)        Pops ST into the specified register. The current value
  16331.                        of the specified register is replaced.
  16332.  
  16333.    FXCH [[ST(num)]]    Exchanges the value in ST with the value in ST(num).
  16334.                        If no operand is specified, ST(0) and ST(1) are
  16335.                        exchanged.
  16336.  
  16337.  
  16338.  
  16339.  17.5.1.2  Integer Transfers
  16340.  
  16341.    The following instructions are available for transferring binary integers:
  16342.  
  16343.    Syntax              Description
  16344.    ──────────────────────────────────────────────────────────────────────────
  16345.    FILD mem            The source must be a 2-, 4-, or 8-byte integer memory
  16346.                        operand. It is interpreted as an integer and converted
  16347.                        to temporary-real format.
  16348.  
  16349.    FIST mem            Copies ST to mem. The destination must be a 2- or
  16350.                        4-byte memory operand. It is automatically converted
  16351.                        from temporary-real format to a word or a doubleword,
  16352.                        depending on the size of the operand. It cannot be
  16353.                        converted to a quadword integer.
  16354.  
  16355.    FISTP mem           Pops ST into mem. The destination must be a 2-, 4-, or
  16356.                        8-byte memory operand. It is automatically converted
  16357.                        from temporary-real format to a word, doubleword, or
  16358.                        quadword integer, depending on the size of the
  16359.                        operand.
  16360.  
  16361.  
  16362.  
  16363.  17.5.1.3  Packed BCD Transfers
  16364.  
  16365.    The following instructions are available for transferring BCD integers:
  16366.  
  16367.    Syntax              Description
  16368.    ──────────────────────────────────────────────────────────────────────────
  16369.    FBLD mem            Pushes a copy of mem into ST. The source must be a
  16370.                        10-byte memory operand. It should contain a packed BCD
  16371.                        value, although no check is made to see that the data
  16372.                        is valid.
  16373.  
  16374.    FBSTP mem           Pops ST into mem. The destination must be a 10-byte
  16375.                        memory operand. The value is rounded to an integer if
  16376.                        necessary and converted to a packed BCD value.
  16377.  
  16378.  
  16379.    The following examples illustrate instructions described throughout this
  16380.    section:
  16381.  
  16382.    Example 1
  16383.  
  16384.                fld     m1                 ; Push m1 into first item
  16385.                fld     st(2)              ; Push third item into first
  16386.                fst     m2                 ; Copy first item to m2
  16387.                fxch    st(2)              ; Exchange first and third items
  16388.                fstp    m1                 ; Pop first item into m1
  16389.  
  16390.    Assuming that registers ST and ST(1) were previously initialized to 3.0
  16391.    and 4.0, the status of the register stack is shown below:
  16392.  
  16393.    ┌────────────────────────────────────────────────────────────────────────┐
  16394.    │ This figure can be found in Section 17.5.1.3 of the manual             │
  16395.    └────────────────────────────────────────────────────────────────────────┘
  16396.  
  16397.    Example 2
  16398.  
  16399.                .DATA
  16400.    shortreal   DD      100 DUP (?)
  16401.    longreal    DQ      100 DUP (?)
  16402.                .CODE
  16403.                .                      ; Assume array shortreal has been
  16404.                .                      ;   filled by previous code
  16405.                .
  16406.                mov     cx,100         ; Initialize loop
  16407.                xor     si,si          ; Clear pointer into shortreal
  16408.                xor     di,di          ; Clear pointer into longreal
  16409.    again:      fld     shortreal[si]  ; Push shortreal
  16410.                fstp    longreal[di]   ; Pop longreal
  16411.                add     si,4           ; Increment source pointer
  16412.                add     di,8           ; Increment destination pointer
  16413.                loop    again          ; Do it again
  16414.  
  16415.    Example 2 illustrates one way of doing run-time type conversions.
  16416.  
  16417.  
  16418.  17.5.2  Loading Constants
  16419.  
  16420.    Constants cannot be given as operands and loaded directly into coprocessor
  16421.    registers. You must allocate memory and initialize the variable to a
  16422.    constant value. The variable can then be loaded by using one of the load
  16423.    instructions described in Section 17.5.1, "Transferring Data to and from
  16424.    Registers."
  16425.  
  16426.    However, special instructions are provided for loading certain constants.
  16427.    You can load 0, 1, pi, and several common logarithmic values directly.
  16428.    Using these instructions is faster and often more precise than loading the
  16429.    values from initialized variables.
  16430.  
  16431.    The instructions that load constants all have the stack top as the implied
  16432.    destination operand. The constant to be loaded is the implied source
  16433.    operand. The instructions are listed below:
  16434.  
  16435.    Syntax              Description
  16436.    ──────────────────────────────────────────────────────────────────────────
  16437.    FLDZ                Pushes 0 into ST
  16438.  
  16439.    FLD1                Pushes 1 into ST
  16440.  
  16441.    FLDPI               Pushes the value of pi into ST
  16442.  
  16443.    FLDL2E              Pushes the value of log2^e into ST
  16444.  
  16445.    FLDL2T              Pushes log2^10 into ST
  16446.  
  16447.    FLDLG2              Pushes log10^2 into ST
  16448.  
  16449.    FLDLN2              Pushes loge^2 ST
  16450.  
  16451.  
  16452.  
  16453.  17.5.3  Transferring Control Data
  16454.  
  16455.    The coprocessor data area, or parts of it, can be stored to memory and
  16456.    later loaded back. One reason for doing this is to save a snapshot of the
  16457.    coprocessor state before going into a procedure, and restore the same
  16458.    status after the procedure. Another reason is to modify coprocessor
  16459.    behavior by storing certain data to main memory, operating on the data
  16460.    with 8086-family instructions, and then loading it back to the coprocessor
  16461.    data area.
  16462.  
  16463.    You can choose to transfer the entire coprocessor data area, the control
  16464.    registers, or just the status or control word. Applications programmers
  16465.    seldom need to load anything other than the status word.
  16466.  
  16467.    All the control-transfer instructions take a single memory operand. Load
  16468.    instructions use the memory operand as the destination; store instructions
  16469.    use it as the source. The coprocessor data area is the implied source for
  16470.    load instructions and the implied destination for store instructions.
  16471.  
  16472.    Each store instruction has two forms. The "wait form" checks for unmasked
  16473.    numeric-error exceptions and waits until they have been handled. The
  16474.    "no-wait" form (which always begins with FN) ignores unmasked exceptions.
  16475.    The instructions are listed below:
  16476.  
  16477.    Syntax                      Description
  16478.    ──────────────────────────────────────────────────────────────────────────
  16479.    FLDCW mem2byte              Loads control word
  16480.  
  16481.    F[[N]]STCW mem2byte         Stores control word
  16482.  
  16483.    F[[N]]STSW mem2byte         Stores status word
  16484.  
  16485.    FLENV mem14byte             Loads environment
  16486.  
  16487.    F[[N]]STENV mem14byte       Stores environment
  16488.  
  16489.    FRSTOR mem94byte            Restores state
  16490.  
  16491.    F[[N]]SAVE mem94byte        Saves state
  16492.  
  16493.  
  16494.    80287/80387 Only
  16495.  
  16496.    Starting with the 80287 coprocessor, the FSTSW and FNSTSW instructions can
  16497.    store data directly to the AX register. This is the only case in which
  16498.    data can be transferred directly between processor and coprocessor
  16499.    registers, as shown below:
  16500.  
  16501.                fstsw   ax
  16502.  
  16503.  
  16504.  17.6  Doing Arithmetic Calculations
  16505.  
  16506.    The math coprocessors offer a rich set of instructions for doing
  16507.    arithmetic. Most arithmetic instructions accept operands in any of the
  16508.    formats discussed in Section 17.3, "Using Coprocessor Instructions."
  16509.  
  16510.    When using memory operands with an arithmetic instruction, make sure you
  16511.    indicate in the name whether you want the memory operand to be treated as
  16512.    a real number or an integer. For example, use FADD to add a real number to
  16513.    the stack top or FIADD to add an integer to the stack top. You do not need
  16514.    to specify the operand type in the instruction if both operands are stack
  16515.    registers, since register values are always real numbers. You cannot do
  16516.    arithmetic on BCD numbers in memory. You must use FBLD to load the numbers
  16517.    into stack registers.
  16518.  
  16519.    The arithmetic instructions are listed below.
  16520.  
  16521.    Addition
  16522.  
  16523.    The following instructions add the source and destination and put the
  16524.    result in the destination:
  16525.  
  16526.    Syntax              Description
  16527.    ──────────────────────────────────────────────────────────────────────────
  16528.    FADD                Classical-stack form. Adds ST and ST(1) and pops the
  16529.                        result into ST. Both operands are destroyed.
  16530.  
  16531.    FADD ST(num),ST     Register form with stack top as source. Adds the two
  16532.                        register values and replaces ST(num) with the result.
  16533.  
  16534.    FADD ST,ST(num)     Register form with stack top as destination. Adds the
  16535.                        two register values and replaces ST with the result.
  16536.  
  16537.    FADD mem            Real-memory form. Adds a real number in mem to ST. The
  16538.                        result replaces ST.
  16539.  
  16540.    FIADD mem           Integer-memory form. Adds an integer in mem to ST. The
  16541.                        result replaces ST.
  16542.  
  16543.    FADDP ST(num),ST    Register-pop form. Adds the two register values and
  16544.                        pops the result into ST(num).
  16545.  
  16546.  
  16547.    Normal Subtraction
  16548.  
  16549.    The following instructions subtract the source from the destination and
  16550.    put the difference in the destination. Thus, the number being subtracted
  16551.    from is replaced by the result.
  16552.  
  16553.    Syntax              Description
  16554.    ──────────────────────────────────────────────────────────────────────────
  16555.    FSUB                Classical-stack form. Subtracts ST from ST(1) and pops
  16556.                        the result into ST. Both operands are destroyed.
  16557.  
  16558.    FSUB ST(num),ST     Register form with stack top as source. Subtracts ST
  16559.                        from ST(num) and replaces ST(num) with the result.
  16560.  
  16561.    FSUB ST,ST(num)     Register form with stack top as destination. Subtracts
  16562.                        ST(num) from ST and replaces ST with the result.
  16563.  
  16564.    FSUB mem            Real-memory form. Subtracts the real number in mem
  16565.                        from ST. The result replaces ST.
  16566.  
  16567.    FISUB mem           Integer-memory form. Subtracts the integer in mem from
  16568.                        ST. The result replaces ST.
  16569.  
  16570.    FSUBP ST(num),ST    Register-pop form. Subtracts ST from ST(num) and pops
  16571.                        the result into ST(num). Both operands are destroyed.
  16572.  
  16573.  
  16574.    Reversed Subtraction
  16575.  
  16576.    The following instructions subtract the destination from the source and
  16577.    put the difference in the destination. Thus, the number subtracted is
  16578.    replaced by the result.
  16579.  
  16580.    Syntax              Description
  16581.    ──────────────────────────────────────────────────────────────────────────
  16582.    FSUBR               Classical-stack form. Subtracts ST(1) from ST and pops
  16583.                        the result into ST. Both operands are destroyed.
  16584.  
  16585.    FSUBR ST(num),ST    Register form with stack top as source. Subtracts
  16586.                        ST(num) from ST and replaces ST(num) with the result.
  16587.  
  16588.    FSUBR ST,ST(num)    Register form with stack top as destination. Subtracts
  16589.                        ST from ST(num) and replaces ST with the result.
  16590.  
  16591.    FSUBR mem           Real-memory form. Subtracts ST from the real number in
  16592.                        mem. The result replaces ST.
  16593.  
  16594.    FISUBR mem          Integer-memory form. Subtracts ST from the integer in
  16595.                        mem. The result replaces ST.
  16596.  
  16597.    FSUBRP ST(num),ST   Register-pop form. Subtracts ST(num) from ST and pops
  16598.                        the result into ST(num). Both operands are destroyed.
  16599.  
  16600.  
  16601.    Multiplication
  16602.  
  16603.    The following instructions multiply the source and destination and put the
  16604.    product in the destination:
  16605.  
  16606.    Syntax              Description
  16607.    ──────────────────────────────────────────────────────────────────────────
  16608.    FMUL                Classical-stack form. Multiplies ST by ST(1) and pops
  16609.                        the result into ST. Both operands are destroyed.
  16610.  
  16611.    FMUL ST(num),ST     Register form with stack top as source. Multiplies the
  16612.                        two register values and replaces ST(num) with the
  16613.                        result.
  16614.  
  16615.    FMUL ST,ST(num)     Register form with stack top as destination.
  16616.                        Multiplies the two register values and replaces ST
  16617.                        with the result.
  16618.  
  16619.    FMUL mem            Real-memory form. Multiplies a real number in mem by
  16620.                        ST. The result replaces ST.
  16621.  
  16622.    FIMUL mem           Integer-memory form. Multiplies an integer in mem by
  16623.                        ST. The result replaces ST.
  16624.  
  16625.    FMULP ST(num),ST    Register-pop form. Multiplies the two register values
  16626.                        and pops the result into ST(num). Both operands are
  16627.                        destroyed.
  16628.  
  16629.  
  16630.    Normal Division
  16631.  
  16632.    The following instructions divide the destination by the source and put
  16633.    the quotient in the destination. Thus, the dividend is replaced by the
  16634.    quotient.
  16635.  
  16636.    Syntax              Description
  16637.    ──────────────────────────────────────────────────────────────────────────
  16638.    FDIV                Classical-stack form. Divides ST(1) by ST and pops the
  16639.                        result into ST. Both operands are destroyed.
  16640.  
  16641.    FDIV ST(num),ST     Register form with stack top as source. Divides
  16642.                        ST(num) by ST and replaces ST(num) with the result.
  16643.  
  16644.    FDIV ST,ST(num)     Register form with stack top as destination. Divides
  16645.                        ST by ST(num) and replaces ST with the result.
  16646.  
  16647.    FDIV mem            Real-memory form. Divides ST by the real number in
  16648.                        mem. The result replaces ST.
  16649.  
  16650.    FIDIV mem           Integer-memory form. Divides ST by the integer in mem.
  16651.                        The result replaces ST.
  16652.  
  16653.    FDIVP ST(num),ST    Register-pop form. Divides ST(num) by ST and pops the
  16654.                        result into ST(num). Both operands are destroyed.
  16655.  
  16656.  
  16657.    Reversed Division
  16658.  
  16659.    The following instructions divide the source by the destination and put
  16660.    the quotient in the destination. Thus, the divisor is replaced by the
  16661.    quotient.
  16662.  
  16663.    Syntax              Description
  16664.    ──────────────────────────────────────────────────────────────────────────
  16665.    FDIVR               Classical-stack form. Divides ST by ST(1) and pops the
  16666.                        result into ST. Both operands are destroyed.
  16667.  
  16668.    FDIVR ST(num),ST    Register form with stack top as source. Divides ST by
  16669.                        ST(num) and replaces ST(num) with the result.
  16670.  
  16671.    FDIVR ST,ST(num)    Register form with stack top as destination. Divides
  16672.                        ST(num) by ST and replaces ST with the result.
  16673.  
  16674.    FDIVR mem           Real-memory form. Divides the real number in mem by
  16675.                        ST. The result replaces ST.
  16676.  
  16677.    FIDIVR mem          Integer-memory form. Divides the integer in mem by ST.
  16678.                        The result replaces ST.
  16679.  
  16680.    FDIVRP ST(num),ST   Register-pop form. Divides ST by ST(num) and pops the
  16681.                        result into ST(num). Both operands are destroyed.
  16682.  
  16683.  
  16684.    Other Operations
  16685.  
  16686.    The following instructions all use the stack top (ST) as an implied
  16687.    destination operand. The result of the operation replaces the value in the
  16688.    stack top. No operand should be given.
  16689.  
  16690.    Syntax              Description
  16691.    ──────────────────────────────────────────────────────────────────────────
  16692.    FABS                Sets the sign of ST to positive.
  16693.  
  16694.    FCHS                Reverses the sign of ST.
  16695.  
  16696.    FRNDINT             Rounds ST to an integer.
  16697.  
  16698.    FSQRT               Replaces the contents of ST with its square root.
  16699.  
  16700.    FSCALE              Scales by powers of 2 by adding the value of ST(1) to
  16701.                        the exponent of the value in ST. This effectively
  16702.                        multiplies the stack-top value by 2 to the power
  16703.                        contained in ST(1). Since the exponent field is an
  16704.                        integer, the value in ST(1) should normally be an
  16705.                        integer.
  16706.  
  16707.    FPREM               Calculates the partial remainder by performing modulo
  16708.                        division on the top two stack registers. The value in
  16709.                        ST is divided by the value in ST(1). The remainder
  16710.                        replaces the value in ST. The value in ST(1) is
  16711.                        unchanged. Since this instruction works by repeated
  16712.                        subtractions, it can take a lot of execution time if
  16713.                        the operands are very different in magnitude. FRPEM is
  16714.                        sometimes used with trigonometric functions.
  16715.  
  16716.    FXTRACT             Breaks a number down into its exponent and mantissa
  16717.                        and pushes the mantissa onto the register stack.
  16718.                        Following the operation, ST contains the value of the
  16719.                        original mantissa and ST(1) contains the value of the
  16720.                        unbiased exponent.
  16721.  
  16722.  
  16723.    Example
  16724.  
  16725.                .DATA
  16726.    a           DD      3.0
  16727.    b           DD      7.0
  16728.    c           DD      2.0
  16729.    posx        DD      0.0
  16730.    negx        DD      0.0
  16731.  
  16732.                .CODE
  16733.                .
  16734.                .
  16735.                .
  16736.    ; Solve quadratic equation - no error checking
  16737.                fld1               ; Get constants 2 and 4
  16738.                fadd    st,st      ; 2 at bottom
  16739.                fld     st         ; Copy it
  16740.                fmul    a          ; = 2a
  16741.  
  16742.                fmul    st(1),st   ; = 4a
  16743.                fxch               ; Exchange
  16744.                fmul    c          ; = 4ac
  16745.  
  16746.                fld     b          ; Load b
  16747.                fmul    st,st      ; = b^2
  16748.                fsubr              ; = b^2 - 4ac
  16749.                                   ; Negative value here produces error
  16750.                fsqrt              ; = square root(b^2 - 4ac)
  16751.                fld     b          ; Load b
  16752.                fchs               ; Make it negative
  16753.                fxch               ; Exchange
  16754.  
  16755.                fld     st         ; Copy square root
  16756.                fadd    st,st(2)   ; Plus version = -b + root((b^2 - 4ac)
  16757.                fxch               ; Exchange
  16758.                fsubp   st(2),st   ; Minus version = -b - root((b^2 - 4ac)
  16759.  
  16760.                fdiv    st,st(2)   ; Divide plus version
  16761.                fstp    posx       ; Store it
  16762.                fdivr              ; Divide minus version
  16763.                fstp    negx       ; Store it
  16764.  
  16765.    This example solves quadratic equations. It does no error checking and
  16766.    fails for some values because it attempts to find the square root of a
  16767.    negative number. You could enhance the code by using the FTST instruction
  16768.    (see Section 17.7.1, "Comparing Operands to Control Program Flow") to
  16769.    check for a negative number or 0 just before the square root is
  16770.    calculated. If b^2 - 4ac is negative or 0, the code can jump to routines
  16771.    that handle special cases for no solution or one solution, respectively.
  16772.  
  16773.  
  16774.  17.7  Controlling Program Flow
  16775.  
  16776.    The math coprocessors have several instructions that set control flags in
  16777.    the status word. The 8087-family control flags can be used with
  16778.    conditional jumps to direct program flow in the same way that 8086-family
  16779.    flags are used. Since the coprocessor does not have jump instructions, you
  16780.    must transfer the status word to memory so that the flags can be used by
  16781.    8086-family instructions.
  16782.  
  16783.    An easy way to use the status word with conditional jumps is to move its
  16784.    upper byte into the lower byte of the processor flags. For example, use
  16785.    the following statements:
  16786.  
  16787.                fstsw   mem16      ; Store status word in memory
  16788.                fwait              ; Make sure coprocessor is done
  16789.                mov     ax,mem16   ; Move to AX
  16790.                sahf               ; Store upper word in flags
  16791.  
  16792.    As noted in Section 17.5.3, "Transferring Control Data," you can save
  16793.    several steps by loading the status word directly to AX on the 80287.
  16794.  
  16795.    Figure 17.3 shows how the coprocessor control flags line up with the
  16796.    processor flags. C3 overwrites the zero flag, C2 overwrites the parity
  16797.    flag, and C0 overwrites the carry flag. C1 overwrites an undefined bit, so
  16798.    it cannot be used directly with conditional jumps, although you can use
  16799.    the TEST instruction to check C1 in memory or in a register. The sign and
  16800.    auxiliary-carry flags are also overwritten, so you cannot count on them
  16801.    being unchanged after the operation.
  16802.  
  16803.    ┌────────────────────────────────────────────────────────────────────────┐
  16804.    │ This figure can be found in Section 17.7 of the manual                 │
  16805.    └────────────────────────────────────────────────────────────────────────┘
  16806.  
  16807.    See Section 15.1.2 for more information on using conditional-jump
  16808.    instructions based on flag status.
  16809.  
  16810.  
  16811.  17.7.1  Comparing Operands to Control Program Flow
  16812.  
  16813.    The 8087-family coprocessors provide several instructions for comparing
  16814.    operands. All these instructions compare the stack top (ST) to a source
  16815.    operand, which may either be specified or implied as ST(1).
  16816.  
  16817.    The compare instructions affect the C3, C2, and C0 control flags. The C1
  16818.    flag is not affected. Table 17.2 shows the flags set for each possible
  16819.    result of a comparison or test.
  16820.  
  16821.    Variations on the compare instructions allow you to pop the stack once or
  16822.    twice, and to compare integers and zero. For each instruction, the stack
  16823.    top is always the implied destination operand. If you do not give an
  16824.    operand, ST(1) is the implied source. Some compare instructions allow you
  16825.    to specify the source as a memory or register operand.
  16826.  
  16827.    Table 17.2 Control-Flag Settings after Compare or Test
  16828.  
  16829.    After FCOM      After FTEST       C3        C2          C0
  16830.    ──────────────────────────────────────────────────────────────────────────
  16831.    ST > source     ST is positive    0         0           0
  16832.  
  16833.    ST < source     ST is negative    0         0           1
  16834.  
  16835.    ST = source     ST is 0           1         0           0
  16836.  
  16837.    Not comparable  ST is NAN or      1         1           1
  16838.                    projective
  16839.                    infinity
  16840.    ──────────────────────────────────────────────────────────────────────────
  16841.  
  16842.  
  16843.    The compare instructions are listed below.
  16844.  
  16845.  
  16846.  17.7.1.1  Compare
  16847.  
  16848.    These instructions compare the stack top to the source. The source and
  16849.    destination are unaffected by the comparison.
  16850.  
  16851.    Syntax              Description
  16852.    ──────────────────────────────────────────────────────────────────────────
  16853.    FCOM                Compares ST to ST(1).
  16854.  
  16855.    FCOM ST(num)        Compares ST to ST(num).
  16856.  
  16857.    FCOM mem            Compares ST to mem. The memory operand can be a four-
  16858.                        or eight-byte real number.
  16859.  
  16860.    FICOM mem           Compares ST to mem. The memory operand can be a two-
  16861.                        or four-byte integer.
  16862.  
  16863.    FTST                Compares ST to 0. The control registers will be
  16864.                        affected as if ST had been compared to 0 in ST(1).
  16865.                        Table 17.2 above shows the possible results.
  16866.  
  16867.  
  16868.  
  16869.  17.7.1.2  Compare and Pop
  16870.  
  16871.    These instructions compare the stack top to the source and then pop the
  16872.    stack. Thus, the destination is destroyed by the comparison.
  16873.  
  16874.    Syntax              Description
  16875.    ──────────────────────────────────────────────────────────────────────────
  16876.    FCOMP               Compares ST to ST(1) and pops ST off the register
  16877.                        stack.
  16878.  
  16879.    FCOMP ST(num)       Compares ST to ST(num) and pops ST off the register
  16880.                        stack.
  16881.  
  16882.    FCOMP mem           Compares ST to mem and pops ST off the register stack.
  16883.                        The operand can be a four- or eight-byte real number.
  16884.  
  16885.    FICOMP mem          Compares ST to mem and pops ST off the register stack.
  16886.                        The operand can be a two- or four-byte integer.
  16887.  
  16888.    FCOMPP              Compares ST to ST(1) and then pops the stack twice.
  16889.                        Both the source and destination are destroyed by the
  16890.                        comparison.
  16891.  
  16892.  
  16893.    Example
  16894.  
  16895.                IFDEF   c287
  16896.                .287
  16897.                ENDIF
  16898.                .DATA
  16899.    down        DD      10.35      ; Sides of a rectangle
  16900.    across      DD      13.07
  16901.    diameter    DD      12.93      ; Diameter of a circle
  16902.    status      DW      ?
  16903.                .CODE
  16904.                .
  16905.                .
  16906.                .
  16907.    ; Get area of rectangle
  16908.                fld     across     ; Load one side
  16909.                fmul    down       ; Multiply by the other
  16910.  
  16911.    ; Get area of circle
  16912.                fld1               ; Load one and
  16913.                fadd    st,st      ;   double it to get constant 2
  16914.                fdivr   diameter   ; Divide diameter to get radius
  16915.                fmul    st,st      ; Square radius
  16916.                fldpi              ; Load pi
  16917.                fmul               ; Multiply it
  16918.  
  16919.    ; Compare area of circle and rectangle
  16920.                fcompp             ; Compare and throw both away
  16921.                IFNDEF  c287
  16922.                fstsw   status     ; Load from coprocessor to memory
  16923.                fwait              ; Wait for coprocessor
  16924.                mov     ax,status  ; Memory to register
  16925.                ELSE
  16926.                fstsw   ax         ;   (for 287+, skip memory)
  16927.                ENDIF
  16928.                sahf               ;   to flags
  16929.                jp      nocomp     ; If parity set, can't compare
  16930.                jz      same       ; If zero set, they're the same
  16931.                jc      rectangle  ; If carry set, rectangle is bigger
  16932.                jmp     circle     ;   else circle is bigger
  16933.  
  16934.    nocomp:     .                  ; Error handler
  16935.                .
  16936.    same:       .                  ; Both equal
  16937.                .
  16938.    rectangle:  .                  ; Rectangle bigger
  16939.                .
  16940.    circle:     .                  ; Circle bigger
  16941.  
  16942.    Notice how conditional blocks are used to enhance 80287 code. If you
  16943.    define the symbol c287 from the command line by using the /D symbol option
  16944.    (see Section B.4, "Defining Assembler Symbols"), the code is smaller and
  16945.    faster, but does not run on an 8087.
  16946.  
  16947.  
  16948.  17.7.2  Testing Control Flags after Other Instructions
  16949.  
  16950.    In addition to the compare instructions, the FXAM and FPREM instructions
  16951.    affect coprocessor control flags.
  16952.  
  16953.    The FXAM instruction sets the value of the control flags based on the type
  16954.    of the number in the stack top (ST). This instruction is used to identify
  16955.    and handle special values, such as infinity, zero, unnormal numbers,
  16956.    denormal numbers, and NANs (not a number). Certain math operations are
  16957.    capable of producing these special-format numbers. A description of them
  16958.    is beyond the scope of this manual. The possible settings of the flags are
  16959.    shown in the on-line Help system.
  16960.  
  16961.    FPREM also sets control flags. Since this instruction must sometimes be
  16962.    repeated to get a correct remainder for large operands, it uses the C2
  16963.    flag to indicate whether the remainder returned is partial (C2 is set) or
  16964.    complete (C2 is clear). If the bit is set, the operation should be
  16965.    repeated.
  16966.  
  16967.    FPREM also returns the least-significant three bits of the quotient in C0,
  16968.    C3, and C1. These bits are useful for reducing operands of periodic
  16969.    transcendental functions, such as sine and cosine, to an acceptable range.
  16970.    The technique is not explained here. The possible settings for each flag
  16971.    are shown in the on-line Help system.
  16972.  
  16973.  
  16974.  17.8  Using Transcendental Instructions
  16975.  
  16976.    The 8087-family coprocessors provide a variety of instructions for doing
  16977.    transcendental calculations, including exponentiation, logarithmic
  16978.    calculations, and some trigonometric functions.
  16979.  
  16980.    Use of these advanced instructions is beyond the scope of this manual.
  16981.    However, the instructions are listed below for reference. All
  16982.    transcendental instructions have implied operands──either ST as a
  16983.    single-destination operand, or ST as the destination and ST(1) as the
  16984.    source.
  16985.  
  16986.    Instruction         Description
  16987.    ──────────────────────────────────────────────────────────────────────────
  16988.    F2XM1               Calculates 2^x-1, where x is the value of the stack
  16989.                        top. The value x must be between 0 and .5, inclusive.
  16990.                        Returning 2^x-1 instead of 2^x allows the instruction
  16991.                        to return the value with greater accuracy. The
  16992.                        programmer can adjust the result to get 2^x.
  16993.  
  16994.    FYL2X               Calculates Y times log2 X, where X is in ST and Y is
  16995.                        in ST(1). The stack is popped, so both X and Y are
  16996.                        destroyed, leaving the result in ST. The value of X
  16997.                        must be positive.
  16998.  
  16999.    FYL2XP1             Calculates Y times log2 (X+1), where X is in ST and Y
  17000.                        is in ST(1). The stack is popped, so both X and Y are
  17001.                        destroyed, leaving the result in ST. The absolute
  17002.                        value of X must be between 0 and the square root of 2
  17003.                        divided by 2. This instruction is more accurate than
  17004.                        FYL2X when computing the log of a number close to 1.
  17005.  
  17006.    FPTAN               Calculates the tangent of the value in ST. The result
  17007.                        is a ratio Y/X, with Y replacing the value in ST and X
  17008.                        pushed onto the stack so that after the instruction,
  17009.                        ST contains Y and ST(1) contains X. The value being
  17010.                        calculated must be a positive number less than pi/4.
  17011.                        The result of the FPTAN instruction can be used to
  17012.                        calculate other trigonometric functions, including
  17013.                        sine and cosine.
  17014.  
  17015.    FPATAN              Calculates the arctangent of the ratio Y/X, where X is
  17016.                        in ST and Y is in ST(1). The stack is popped, so both
  17017.                        X and Y are destroyed, leaving the result in ST. Both
  17018.                        X and Y must be positive numbers less than infinity,
  17019.                        and Y must be less than X. The result of the FPATAN
  17020.                        instruction can be used to calculate other inverse
  17021.                        trigonometric functions, including arcsine and
  17022.                        arccosine.
  17023.  
  17024.  
  17025.  
  17026.  17.9  Controlling the Coprocessor
  17027.  
  17028.    Additional instructions are available for controlling various aspects of
  17029.    the coprocessor. With the exception of FINIT, these instructions are
  17030.    generally used only by systems programmers. They are summarized below, but
  17031.    not fully explained or illustrated. Some instructions have a wait version
  17032.    and a no-wait version. The no-wait versions have N as the second letter.
  17033.  
  17034.    Syntax              Description
  17035.    ──────────────────────────────────────────────────────────────────────────
  17036.    F[[N]]INIT          Resets the coprocessor and restores all the default
  17037.                        conditions in the control and status words. It is a
  17038.                        good idea to use this instruction at the start and end
  17039.                        of your program. Placing it at the start ensures that
  17040.                        no register values from previous programs affect your
  17041.                        program. Placing it at the end ensures that register
  17042.                        values from your program will not affect later
  17043.                        programs.
  17044.  
  17045.    F[[N]]CLEX          Clears all exception flags and the busy flag of the
  17046.                        status word. It also clears the error-status flag on
  17047.                        the 80287, or the interrupt-request flag on the 8087.
  17048.  
  17049.    FINCSTP             Adds 1 to the stack pointer in the status word. Do not
  17050.                        use to pop the register stack. No tags or registers
  17051.                        are altered.
  17052.  
  17053.    FDECSTP             Subtracts 1 from the stack pointer in the status word.
  17054.                        No tags or registers are altered.
  17055.  
  17056.    FREE ST(num)        Marks the specified register as empty.
  17057.  
  17058.    FNOP                Copies the stack top to itself, thus padding the
  17059.                        executable file and taking up processing time without
  17060.                        having any effect on registers or memory.
  17061.  
  17062.  
  17063.    8087 Only
  17064.  
  17065.    The 8087 has the instructions FDISI, FNDISI, FENI, and FNENI. These
  17066.    instructions can be used to enable or disable interrupts. The 80287
  17067.    coprocessor permits these instructions, but ignores them. Applications
  17068.    programmers will not normally need these instructions. Systems programmers
  17069.    should avoid using them so that their programs are portable to all
  17070.    coprocessors.
  17071.  
  17072.  
  17073.  
  17074.  ────────────────────────────────────────────────────────────────────────────
  17075.  Chapter 18:  Controlling the Processor
  17076.  
  17077.  
  17078.    The 8086-family processors provide instructions for processor control.
  17079.    These instructions are available on all 8086-family processors.
  17080.  
  17081.    System-control instructions have limited use in applications programming.
  17082.    They are primarily used by systems programmers who write operating systems
  17083.    and other control software. Since systems programming is beyond the scope
  17084.    of this manual, the systems-control instructions are summarized, but not
  17085.    explained in detail, in the sections below.
  17086.  
  17087.    This chapter ends with a description of all the directives that enable the
  17088.    instruction sets for the various processors in the 8086 family.
  17089.  
  17090.  
  17091.  18.1  Controlling Timing and Alignment
  17092.  
  17093.    The NOP instruction takes up one byte of memory but does not have any
  17094.    effect when executed. The purpose of this instruction is generally to fill
  17095.    up space in the code segment; primarily, it is used to pad executable code
  17096.    for alignment.
  17097.  
  17098.    Although NOP has no effect, it does take a few clock cycles to execute. In
  17099.    a sense, NOP does do something──it is exactly equivalent to the following
  17100.    instruction:
  17101.  
  17102.                xchg    ax,ax       ; Exchange AX with itself
  17103.  
  17104.    Because NOP does use up some clock time, you can use it in timing loops by
  17105.    executing it many times. However, when writing a program for use on
  17106.    different machines, avoid using this technique. Timing loops that use NOP
  17107.    take different lengths of time on different machines. A better way to
  17108.    control timing is to use the DOS Get Time function, since it is based on
  17109.    the computer's internal clock rather than on the speed of the processor.
  17110.  
  17111.    QuickAssembler automatically inserts NOP instructions for padding when you
  17112.    use the ALIGN or EVEN directive (see Section 6.7, "Aligning Data") to
  17113.    align data or code on a given boundary.
  17114.  
  17115.  
  17116.  18.2  Controlling the Processor
  17117.  
  17118.    The LOCK, WAIT, ESC, and HLT instructions control different aspects of the
  17119.    processor.
  17120.  
  17121.    These instructions can be used to control processes handled by external
  17122.    coprocessors. The 8087-family coprocessors are the coprocessors most
  17123.    commonly used with 8086-family processors, but 8086-based machines can
  17124.    work with other coprocessors if they have the proper hardware and control
  17125.    software.
  17126.  
  17127.    These instructions are summarized below:
  17128.  
  17129.    Instruction         Description
  17130.    ──────────────────────────────────────────────────────────────────────────
  17131.    LOCK                Locks out other processors until a specified
  17132.                        instruction is finished. This is a prefix that
  17133.                        precedes the instruction. It can be used to make sure
  17134.                        that a coprocessor does not change data being worked
  17135.                        on by the processor.
  17136.  
  17137.    WAIT                Instructs the processor to do nothing until it
  17138.                        receives a signal that a coprocessor has finished with
  17139.                        a task being performed at the same time. See Section
  17140.                        17.4, "Coordinating Memory Access," for information
  17141.                        on using WAIT or its coprocessor equivalent, FWAIT,
  17142.                        with the 8087-family coprocessors.
  17143.  
  17144.    ESC                 Provides an instruction and possibly a memory operand
  17145.                        for use by a coprocessor. QuickAssembler automatically
  17146.                        inserts ESC instructions when required for use with
  17147.                        8087-family coprocessors.
  17148.  
  17149.    HLT                 Stops the processor until an interrupt is received. It
  17150.                        can be used in place of an endless loop if a program
  17151.                        needs to wait for an interrupt.
  17152.  
  17153.  
  17154.  
  17155.  18.3  Processor Directives
  17156.  
  17157.    Processor and coprocessor directives define the instruction set that is
  17158.    recognized by QuickAssembler. They are listed and explained below:
  17159.  
  17160.    Directive           Description
  17161.    ──────────────────────────────────────────────────────────────────────────
  17162.    .8086               The .8086 directive enables assembly of instructions
  17163.                        for the 8086 and 8088 processors and the 8087
  17164.                        coprocessor. It disables assembly of the instructions
  17165.                        unique to the 80186, 80286, and 80386 processors.
  17166.  
  17167.                        This is the default mode and is used if no instruction
  17168.                        set directive is specified. Using the default
  17169.                        instruction set ensures that your program can be used
  17170.                        on all 8086-family processors. However, if you choose
  17171.                        this directive, your program will not take advantage
  17172.                        of the more powerful instructions available on more
  17173.                        advanced processors.
  17174.  
  17175.    .186                The .186 directive enables assembly of the 8086
  17176.                        processor instructions, 8087 coprocessor instructions,
  17177.                        and the additional instructions for the 80186
  17178.                        processor.
  17179.  
  17180.    .286                The .286 directive enables assembly of the 8086
  17181.                        instructions plus the additional nonprivileged
  17182.                        instructions of the 80286 processor. It also enables
  17183.                        80287 coprocessor instructions. If privileged
  17184.                        instructions were previously enabled, the .286
  17185.                        directive disables them.
  17186.  
  17187.                        This directive should be used for programs that will
  17188.                        be executed only by an 80186, 80286, or 80386
  17189.                        processor. For compatibility with early versions of
  17190.                        the Macro Assembler, the .286C directive is also
  17191.                        available. It is equivalent to the .286 directive.
  17192.  
  17193.    .8087               The .8087 directive enables assembly of instructions
  17194.                        for the 8087 math coprocessor and disables assem-bly
  17195.                        of instructions unique to the 80287 coprocessor. It
  17196.                        also specifies the IEEE format for encoding
  17197.                        floating-point variables.
  17198.  
  17199.                        This is the default mode and is used if no coprocessor
  17200.                        directive is specified. This directive should be used
  17201.                        for programs that must run with either the 8087,
  17202.                        80287, or 80387 coprocessors.
  17203.  
  17204.    .287                The .287 directive enables assembly of instructions
  17205.                        for the 8087 floating-point coprocessor and the
  17206.                        additional instructions for the 80287. It also
  17207.                        specifies the IEEE format for encoding floating-point
  17208.                        variables.
  17209.  
  17210.                        Coprocessor instructions are optimized if you use this
  17211.                        directive rather than the .8087 directive. Therefore,
  17212.                        you should use it if you know your program will never
  17213.                        need to run under an 8087 coprocessor. See Section
  17214.                        17.4, "Coordinating Memory Access," for an
  17215.                        explanation.
  17216.  
  17217.  
  17218.    If you do not specify any processor directives, QuickAssembler uses the
  17219.    following defaults:
  17220.  
  17221.    1. 8086/8088 processor instruction set
  17222.  
  17223.    2. 8087 coprocessor instruction set
  17224.  
  17225.    3. IEEE format for floating-point variables
  17226.  
  17227.    Normally, the processor and coprocessor directives can be used at the
  17228.    start of the source file to define the instruction sets for the entire
  17229.    assembly. However, it is possible to use different processor directives at
  17230.    different points in the source file to change assumptions for a section of
  17231.    code. For instance, you might have processor-specific code in different
  17232.    parts of the same source file. You can also turn privileged instructions
  17233.    on and off or allow unusual combinations of the processor and coprocessor.
  17234.  
  17235.    There are two limitations on changing the processor or coprocessor:
  17236.  
  17237.    1. The directives must be given outside segments. You must end the current
  17238.       segment, give the processor directive, and then open another segment.
  17239.       See Section 5.1.5, "Using Predefined Segment Equates," for an example
  17240.       of changing the processor directives with simplified segment
  17241.       directives.
  17242.  
  17243.    2. You can specify a lower-level coprocessor with a higher-level
  17244.       coprocessor, but an error message will be generated if you try to
  17245.       specify a lower-level processor with a higher-level coprocessor.
  17246.  
  17247.    The coprocessor directives have the opposite effect of the .MSFLOAT
  17248.    directive. .MSFLOAT turns off coprocessor instruction sets and enables the
  17249.    Microsoft Binary format for floating-point variables. Any coprocessor
  17250.    instruction turns on the specified coprocessor instruction set and enables
  17251.    IEEE format for floating-point variables.
  17252.  
  17253.    Examples
  17254.  
  17255.    ; .MSFLOAT affects the source file until turned off
  17256.                .MSFLOAT
  17257.                .8087              ; Ignored
  17258.  
  17259.    ; Illegal - can't use 8086 with 80287
  17260.                .8086
  17261.                .287
  17262.  
  17263.  
  17264.  
  17265.  ────────────────────────────────────────────────────────────────────────────
  17266.  Appendix A:  Mixed-Language Mechanics
  17267.  
  17268.  
  17269.    The QuickAssembler PROC statement automates most details of interfacing to
  17270.    QuickC, as well as to other Microsoft high-level languages. When you use
  17271.    PROC with a parameter list or USES clause as described in Section 15.3.4,
  17272.    or when you use the LOCAL directive, the assembler generates code that
  17273.    properly enters and exits the procedure. The assembler also determines the
  17274.    location of each parameter on the stack for you. You refer to each
  17275.    parameter by a meaningful name, and the assembler translates each
  17276.    parameter name into the actual memory reference.
  17277.  
  17278.    The main purpose of this appendix is to show you what code the assembler
  17279.    generates when you use the LOCAL directive or expanded features of the
  17280.    PROC directive. However, you can write this code yourself rather than
  17281.    letting the assembler generate it. Doing so requires significant extra
  17282.    work, but it does give you complete control over your procedure.
  17283.  
  17284.    Using simplified segment directives is the easiest way to interface with a
  17285.    Microsoft high-level language (including QuickC). The simplified segment
  17286.    directives generate segment definitions similar to the ones generated by
  17287.    high-level languages and guarantee compatibility in the use of segment
  17288.    names and conventions. If you want to use full segment definitions, see
  17289.    Chapter 5, "Defining Segment Structure," for a description of the
  17290.    segments used in Microsoft languages.
  17291.  
  17292.  
  17293.  A.1  Writing the Assembly Procedure
  17294.  
  17295.    The Microsoft BASIC, C, FORTRAN, and Pascal compilers use roughly the same
  17296.    interface for procedure calls. This section describes the interface, so
  17297.    that you can call assembly procedures using essentially the same methods
  17298.    as Microsoft compiler-generated code. Procedures written with these
  17299.    methods can be called recursively.
  17300.  
  17301.    The standard assembly-interface method consists of these steps:
  17302.  
  17303.    1. Setting up the procedure
  17304.  
  17305.    2. Entering the procedure
  17306.  
  17307.    3. Allocating local data (optional)
  17308.  
  17309.    4. Preserving register values
  17310.  
  17311.    5. Accessing parameters
  17312.  
  17313.    6. Returning a value (optional)
  17314.  
  17315.    7. Exiting the procedure
  17316.  
  17317.    The PROC statement, when used with a parameter list or USES clause,
  17318.    automates steps 1 and 2, and simplifies step 5 for you. The LOCAL
  17319.    directive automates step 3, and the USES clause automates step 4. Finally,
  17320.    if you use any of these features, the assembler automatically generates
  17321.    all the proper code to exit (step 7) wherever it encounters a RET
  17322.    directive. (However, the RETF and RETN statements never generate automatic
  17323.    code.)
  17324.  
  17325.    Sections A.1.1-A.1.7 describe these steps.
  17326.  
  17327.  
  17328.  A.1.1  Setting Up the Procedure
  17329.  
  17330.    The linker cannot combine the assembly procedure with the calling program
  17331.    unless compatible segments are used and unless the procedure itself is
  17332.    declared properly. The following points may be helpful:
  17333.  
  17334.    1. Use the .MODEL directive at the beginning of the source file; this
  17335.       directive automatically causes the appropriate kind of returns to be
  17336.       generated (NEAR for small or compact model, FAR otherwise). Modules
  17337.       called from Pascal should be declared as .MODEL LARGE; modules called
  17338.       from BASIC should be .MODEL MEDIUM.
  17339.  
  17340.    2. Use the simplified segment directives: .CODE to declare the code
  17341.       segment and .DATA to declare the data segment. (Having a code segment
  17342.       is sufficient if you do not have data declarations.)
  17343.  
  17344.    3. Tie procedure label must be public. This makes the procedure available
  17345.       to be called by other modules. If you specify a language type with the
  17346.       .MODEL directive, the assembler automatically makes all procedure names
  17347.       public, but you must use the PUBLIC directive if you don't specify the
  17348.       language. Also, any data you want to make public to other modules must
  17349.       be declared as PUBLIC.
  17350.  
  17351.    4. Global data or procedures accessed by the routine (but defined in other
  17352.       modules) must be declared EXTRN.
  17353.  
  17354.  
  17355.  A.1.2  Entering the Procedure
  17356.  
  17357.    Two instructions begin the procedure:
  17358.  
  17359.                push    bp
  17360.                mov     bp,sp
  17361.  
  17362.    This sequence establishes BP as the framepointer. The framepointer is used
  17363.    to access parameters and local data, which are located on the stack. SP
  17364.    cannot be used for this purpose because it is not an index or base
  17365.    register. Also, the value of SP may change as more data is pushed onto the
  17366.    stack. However, the value of the base register (BP) will remain constant
  17367.    throughout the procedure, so that each parameter can be addressed as a
  17368.    fixed displacement from the location pointed to by BP.
  17369.  
  17370.    The instruction sequence above first saves the value of BP, since it will
  17371.    be needed by the calling procedure as soon as the current procedure
  17372.    terminates. Then BP is loaded with the value of SP in order to capture the
  17373.    value of the stack pointer at the time of entry to the procedure.
  17374.  
  17375.    The PROC statement generates these two lines of code automatically if you
  17376.    use a parameter list, LOCAL directive, or USES clause.
  17377.  
  17378.    ──────────────────────────────────────────────────────────────────────────
  17379.    NOTE  If you alter the direction flag with the STD instruction, make sure
  17380.    you reset this flag with the CLD instruction before you exit.
  17381.    ──────────────────────────────────────────────────────────────────────────
  17382.  
  17383.  
  17384.  A.1.3  Allocating Local Data (Optional)
  17385.  
  17386.    Local variables are also called dynamic, stack, or automatic variables.
  17387.  
  17388.    An assembly procedure can use the same technique for implementing local
  17389.    data used by high-level languages. To set up local data space, decrease
  17390.    the contents of SP in the third instruction of the procedure. (To ensure
  17391.    correct execution, you should always increase or decrease SP by an even
  17392.    amount.) Decreasing SP reserves space on the stack for the local data. The
  17393.    space must be restored at the end of the procedure.
  17394.  
  17395.                push   bp
  17396.                mov    bp,sp
  17397.                sub    sp,space
  17398.  
  17399.    In the code above, space is the total size in bytes of the local data.
  17400.    Local variables are then accessed as fixed, negative displacements from
  17401.    the location pointed to by BP.
  17402.  
  17403.    Example
  17404.  
  17405.                push   bp
  17406.                mov    bp,sp
  17407.                sub    sp,4
  17408.                .
  17409.                .
  17410.                .
  17411.                mov    WORD PTR [bp-2],0
  17412.                mov    WORD PTR [bp-4],0
  17413.  
  17414.    The example above uses two local variables, each of which is two bytes in
  17415.    size. SP is decreased by 4, since there are four bytes total of local
  17416.    data. Later, each of the variables is initialized to 0. These variables
  17417.    are never formally declared with any assembler directive; the programmer
  17418.    must keep track of them manually.
  17419.  
  17420.    The LOCAL directive uses this same method for creating local variables.
  17421.    However, when you use LOCAL, you can refer to a local variable by a
  17422.    symbolic name rather than by a reference, such as WORD PTR [bp-2].
  17423.  
  17424.  
  17425.  A.1.4  Preserving Register Values
  17426.  
  17427.    A procedure called from any of the Microsoft high-level languages should
  17428.    preserve the values of SI, DI, SS, and DS (in addition to BP, which is
  17429.    already saved). Therefore, push any of these register values that the
  17430.    procedure alters. If the procedure does not change the value of any of
  17431.    these registers, the registers do not need to be pushed.
  17432.  
  17433.    The recommended method (used by high-level languages) is to save registers
  17434.    after the framepointer is set and local data (if any) is allocated.
  17435.  
  17436.                push   bp           ; Save old framepointer
  17437.                mov    bp,sp        ; Establish current framepointer
  17438.                sub    sp,4         ; Allocate local data space
  17439.                push   si           ; Save SI and DI
  17440.                push   di
  17441.                .
  17442.                .
  17443.                .
  17444.  
  17445.    In the example above, DI and SI (in that order) must be popped from the
  17446.    stack before the end of the procedure.
  17447.  
  17448.    The USES clause in a PROC statement causes the assembler to generate this
  17449.    same code.
  17450.  
  17451.  
  17452.  A.1.5  Accessing Parameters
  17453.  
  17454.    When you use PROC with a parameter list, the assembler calculates the
  17455.    location of each parameter on the stack. This section shows how the
  17456.    assembler determines these locations. If you do not use a parameter list,
  17457.    you must calculate parameter locations yourself and refer to them
  17458.    explicitly by their offsets from BP. Otherwise, you can refer to each
  17459.    parameter by the name you gave it in the parameter list.
  17460.  
  17461.    To write instructions that can access parameters, consider the general
  17462.    picture of the stack frame after a procedure call, as illustrated in
  17463.    Figure A.1.
  17464.  
  17465.    ┌────────────────────────────────────────────────────────────────────────┐
  17466.    │ This figure can be found in Section A.1.5 of the manual                │
  17467.    └────────────────────────────────────────────────────────────────────────┘
  17468.  
  17469.    When determining the order of parameters on the stack, note that the C
  17470.    calling convention (the default for QuickC) specifies that parameters are
  17471.    passed in the reverse order they appear in source code. The non-C calling
  17472.    convention (which you can specify in QuickC with the pascal or fortran
  17473.    keyword) specifies that parameters are passed in the same order they
  17474.    appear in source code.
  17475.  
  17476.    The stack frame for the procedure is established by the following
  17477.    sequence:
  17478.  
  17479.    1. The calling program pushes each of the parameters on the stack, after
  17480.       which SP points to the last parameter pushed.
  17481.  
  17482.    2. The calling program issues a CALL instruction, which causes the return
  17483.       address (the place in the calling program to which control will
  17484.       ultimately return) to be placed on the stack. This address may be
  17485.       either two bytes long (for near calls) or four bytes long (for far
  17486.       calls). SP now points to this address.
  17487.  
  17488.    3. The first instruction of the called procedure saves the old value of
  17489.       BP, with the instruction push bp. SP now points to the saved copy of
  17490.       BP.
  17491.  
  17492.    4. BP is used to capture the current value of SP, with the instruction mov
  17493.       bp,sp. BP therefore now points to the old value of BP.
  17494.  
  17495.    5. Whereas BP remains constant throughout the procedure, SP may be
  17496.       decreased to provide room on the stack for local data or saved
  17497.       registers.
  17498.  
  17499.    In general, the displacement (from the location pointed to by BP) for a
  17500.    parameter X is equal to:
  17501.  
  17502.    2 + size of return address + total size of parameters between X and BP
  17503.  
  17504.    For example, consider a FAR procedure that has received one parameter, a
  17505.    two-byte address. The displacement of the parameter would be:
  17506.  
  17507.    Argument's displacement =  2 + size of return address
  17508.                            =  2 + 4
  17509.                            =  6
  17510.  
  17511.    The argument can thus be loaded into BX with the following instruction:
  17512.  
  17513.                mov     bx,[bp+6]
  17514.  
  17515.    Once you determine the displacement of each parameter, you may want to use
  17516.    string equates or structures so that the parameter can be referenced with
  17517.    a single identifier name in your assembly source code. For example, the
  17518.    parameter above at BP+6 can be conveniently accessed if you put the
  17519.    following statement at the beginning of the assembly source file:
  17520.  
  17521.    Arg1        EQU     <[bp+6]>
  17522.  
  17523.    You could then refer to this parameter as Arg1 in any instruction. Use of
  17524.    this feature is optional.
  17525.  
  17526.    ──────────────────────────────────────────────────────────────────────────
  17527.    NOTE  Microsoft high-level languages always push segment addresses before
  17528.    pushing offset addresses. Furthermore, when pushing arguments larger than
  17529.    two bytes, high-order words are always pushed before low-order words.
  17530.  
  17531.    This standard for pushing segment addresses before pushing offset
  17532.    addresses facilitates the use of the LES and LDS instructions, as
  17533.    described in Chapter 3, "Writing Assembly Modules for C Programs."
  17534.    ──────────────────────────────────────────────────────────────────────────
  17535.  
  17536.  
  17537.  A.1.6  Returning a Value (Optional)
  17538.  
  17539.    The assembler does not generate code to return a value. If you want your
  17540.    procedure to return a value, you must take care of the details yourself.
  17541.  
  17542.    Microsoft BASIC, C, FORTRAN, and Pascal share similar conventions for
  17543.    receiving return values. The conventions are the same when the data type
  17544.    to be returned is simple (that is, not an array or structured type) and is
  17545.    no more than four bytes long. This includes all NEAR and FAR address types
  17546.    (in other words, all pointers and all parameters passed by reference).
  17547.  
  17548.    Data Size           Returned in Register
  17549.    ──────────────────────────────────────────────────────────────────────────
  17550.    1 byte              AL
  17551.  
  17552.    2 bytes             AX
  17553.  
  17554.    4 bytes             High-order portion (or segment address) in DX;
  17555.                        low-order portion (or offset address) in AX
  17556.  
  17557.  
  17558.    When the return value is larger than four bytes, a procedure called by C
  17559.    must allocate space for the return value and then place its address in
  17560.    DX:AX. You can create space for the return value by simply declaring it in
  17561.    a data segment.
  17562.  
  17563.    If your assembly procedure uses the non-C calling convention, it must use
  17564.    a special convention in order to return floating-point values, records,
  17565.    user-defined types and arrays, and values larger than four bytes. This
  17566.    convention is presented below.
  17567.  
  17568.    BASIC/FORTRAN/Pascal Long Return Values
  17569.  
  17570.    To create an interface for long return values, modules using the non-C
  17571.    calling convention take the following actions before they call your
  17572.    procedure:
  17573.  
  17574.    1. The calling modules create space, somewhere in the stack segment, to
  17575.       hold the actual return value.
  17576.  
  17577.    2. When the call to your procedure is made, an extra parameter is passed
  17578.       containing the offset address of the actual return value. This
  17579.       parameter is placed immediately above the return address. (In other
  17580.       words, this parameter is the last one pushed.)
  17581.  
  17582.    3. The segment address of the return value is contained in both SS and DS.
  17583.  
  17584.    The extra parameter (containing the offset address of the return value) is
  17585.    always located at BP+6. Furthermore, its presence automatically increases
  17586.    the displacement of all other parameters by 2, as shown in Figure A.2.
  17587.  
  17588.    ┌────────────────────────────────────────────────────────────────────────┐
  17589.    │ This figure can be found in Section A.1.6 of the manual                │
  17590.    └────────────────────────────────────────────────────────────────────────┘
  17591.  
  17592.    Your assembly procedure will successfully return a long value if you
  17593.    follow these steps:
  17594.  
  17595.    1. Put the data for the return value at the location pointed to by the
  17596.       return value offset.
  17597.  
  17598.    2. Copy the return-value offset (located at BP+6) to AX, and copy SS to
  17599.       DX. This is necessary because the calling module expects DX:AX to point
  17600.       to the return value.
  17601.  
  17602.    3. Exit the procedure as described in the next section.
  17603.  
  17604.  
  17605.  A.1.7  Exiting the Procedure
  17606.  
  17607.    Several steps may be involved in terminating the procedure:
  17608.  
  17609.    1. If any of the registers SS, DS, SI, or DI have been saved, these must
  17610.       be popped off the stack in the reverse order that they were saved.
  17611.  
  17612.    2. If local data space was allocated at the beginning of the procedure, SP
  17613.       must be restored with the instruction mov sp,bp.
  17614.  
  17615.    3. Restore BP with pop bp. This step is always necessary.
  17616.  
  17617.    4. Finally, return to the calling program with ret. If the BASIC, FORTRAN,
  17618.       or Pascal calling convention is in use, you can use the ret n form of
  17619.       the instruction to adjust the stack with respect to the parameters that
  17620.       were pushed by the caller. (If the procedure is called by a C module,
  17621.       the calling module will perform this adjustment.)
  17622.  
  17623.    Examples
  17624.  
  17625.                pop    bp
  17626.                ret
  17627.  
  17628.    The example above shows the simplest possible exit sequence. No registers
  17629.    were saved, no local data space was allocated, and the C calling
  17630.    convention is in use.
  17631.  
  17632.                pop    di           ; Pop saved regs
  17633.                pop    si
  17634.                mov    sp,bp        ; Remove local data space
  17635.                pop    bp           ; Restore old framepointer
  17636.                ret    6            ; Exit, and restore 6 byte of args
  17637.  
  17638.    The example above shows an exit sequence for a procedure that has
  17639.    previously saved SI and DI, allocated local data space, and uses a non-C
  17640.    calling convention. The procedure must therefore use ret 6 (where n is 6)
  17641.    to restore the six bytes of parameters on the stack.
  17642.  
  17643.    Assuming you use one of the automated features described above (such as a
  17644.    parameter list or LOCAL directive), the assembler generates all the code
  17645.    to properly exit from a procedure whenever it encounters a RET
  17646.    instruction. However, the assembler does not generate any exit code when
  17647.    you use the directives RETN or RETF.
  17648.  
  17649.  
  17650.  A.2  Calls from Modules Using C Conventions
  17651.  
  17652.    Most of the details below are automated when you use simplified segment
  17653.    directives and the expanded features of the PROC directive. Make sure to
  17654.    declare both a language type and a memory model with the .MODEL directive.
  17655.  
  17656.    This section reviews all the steps taken when you use the C language type.
  17657.    In addition to the steps outlined in Section A.1, the assembler observes
  17658.    the following rules to set up an interface to C.
  17659.  
  17660.    Follow these rules if you want to manually establish this interface:
  17661.  
  17662.    1. Declare procedures called from C as FAR if the C module is compiled in
  17663.       large, huge, or medium model, and NEAR if the C module is compiled in
  17664.       small or compact model (although the near and far keywords can override
  17665.       these defaults). The correct declaration for the procedure is made
  17666.       implicitly when you use the .MODEL directive. Note that tiny memory
  17667.       model is not supported by QuickC 2.0.
  17668.  
  17669.    2. Observe the C calling convention.
  17670.  
  17671.       a. Return with a simple ret instruction. Do not restore the stack with
  17672.          ret size, since the calling C routine will restore the stack itself
  17673.          as soon as it resumes control.
  17674.  
  17675.       b. Parameters are placed on the stack in the reverse order that they
  17676.          appear in the C source code. The first parameter will be lowest in
  17677.          memory (because it is placed on the stack last and the stack grows
  17678.          downward).
  17679.  
  17680.       c. By default, C parameters are passed by value, except for arrays,
  17681.          which are passed by reference. As a rule, do not expect an address
  17682.          to be placed on the stack, unless the C code specifically refers to
  17683.          a pointer or array in the function call or prototype.
  17684.  
  17685.       3. Observe the C naming convention.
  17686.  
  17687.       Include an underscore (_) in front of any name that will be shared
  17688.       publicly with C. C recognizes only the first eight characters of any
  17689.       name, so do not make names shared with C longer than eight characters.
  17690.       Also, if you plan to link with the /NOIGNORECASE option, remember that
  17691.       C is case sensitive and does not convert names to uppercase. To
  17692.       preserve lowercase names in public symbols, choose Preserve Case or
  17693.       Preserve Extrn from the Assembler Flags dialog box, or assemble with
  17694.       the /Cl or /Cx option on the QCL command line.
  17695.  
  17696.    In the example program below, C calls an assembly procedure that
  17697.    calculates "A x 2^B," where A and B are the first and second parameters,
  17698.    respectively. The calculation is performed by shifting the bits in A to
  17699.    the left, B times.
  17700.  
  17701.    extern int power2( int, int ),
  17702.  
  17703.    main  ()
  17704.    {
  17705.          printf( "3 times 2 to the power of 5 is %d\n",
  17706.                   power2( 3, 5 ) );
  17707.    }
  17708.  
  17709.    The C program uses an extern declaration to create an interface with the
  17710.    assembly procedure. No special keywords are required because the assembly
  17711.    procedure will use the C calling convention.
  17712.  
  17713.    To understand how to write the assembly procedure, consider how the
  17714.    parameters are placed on the stack, as illustrated in Figure A.3.
  17715.  
  17716.    ┌────────────────────────────────────────────────────────────────────────┐
  17717.    │ This figure can be found in Section A.2 of the manual                  │
  17718.    └────────────────────────────────────────────────────────────────────────┘
  17719.  
  17720.    The return address is two bytes long, assuming that the C module is
  17721.    compiled in small or compact model. If the C module is compiled in large,
  17722.    huge, or medium model, the addresses of Arg 1 and Arg 2 are each increased
  17723.    by 2, to BP+6 and BP+8, respectively, because the return address will be
  17724.    four bytes long.
  17725.  
  17726.    Arg 1 (parameter 1) is lower in memory than Arg 2, because C pushes
  17727.    arguments in the reverse order that they appear. Each argument is passed
  17728.    by value.
  17729.  
  17730.    The assembly procedure can be written as follows:
  17731.  
  17732.                .MODEL      small
  17733.                .CODE
  17734.                PUBLIC      _power2
  17735.    _power2           PROC
  17736.                push                bp      ; Entry sequence - save old BP
  17737.                mov         bp,sp           ; Set stack framepointer
  17738.  
  17739.                mov         ax,[bp+4]       ; Load Arg1 into AX
  17740.                mov         cx,[bp+6]       ; Load Arg2 into CX
  17741.                shl         ax,cl           ; AX = AX * (2 to power of CX)
  17742.                                            ; Leave return value in AX
  17743.  
  17744.                pop         bp              ; Exit sequence - restore old BP
  17745.                ret                         ; Return
  17746.    _power2           ENDP
  17747.                END
  17748.  
  17749.    The example above assumes that the C module is compiled in small model.
  17750.    The parameter offsets and the .MODEL directive will change for different
  17751.    models.
  17752.  
  17753.    Note that ret without a size variable is used, since the caller will
  17754.    adjust the stack upon return from the call.
  17755.  
  17756.  
  17757.  A.3  Calls from Non-C Modules
  17758.  
  17759.    In your C programs you can specify the pascal or fortran function type.
  17760.    These keywords are equivalent: they both specify use of non-C calling and
  17761.    naming conventions. Furthermore, you may want to interface to languages
  17762.    other than C (which you can do by linking .OBJ files together outside the
  17763.    environment). In all these cases, make sure you specify BASIC, FORTRAN, or
  17764.    Pascal as the language type with the .MODEL directive. Alternately, you
  17765.    can specify the language as part of the procedure if you are using the
  17766.    extended PROC directive.
  17767.  
  17768.    This section reviews all the steps taken when you use a non-C language
  17769.    type. In addition to the steps outlined in Section A.1, the assembler
  17770.    observes the following rules to set up an interface to a language using a
  17771.    non-C calling convention.
  17772.  
  17773.    Follow these rules if you want to manually establish an interface to a
  17774.    high-level language:
  17775.  
  17776.    1. If the procedure is called from Microsoft BASIC, Pascal, or FORTRAN,
  17777.       make sure to declare the procedure as FAR, or use the .MODEL directive
  17778.       to specify medium or large memory model. BASIC always uses medium
  17779.       memory model; Pascal uses large memory model.
  17780.  
  17781.    2. Observe the non-C calling convention.
  17782.  
  17783.       a. Upon exit, the procedure must reset SP to the value it had before
  17784.          the parameters were placed on the stack. This is accomplished with
  17785.          the instruction ret size, where size is the total size in bytes of
  17786.          all the parameters.
  17787.  
  17788.       b. Parameters are placed on the stack in the same order in which they
  17789.          appear in the high-level language source code. The first parameter
  17790.          will be highest in memory (because it is placed on the stack first
  17791.          and the stack grows downward).
  17792.  
  17793.       c. Each language has different defaults for passing parameters by value
  17794.          or reference. When a language passes by reference, it places a data
  17795.          pointer on the stack. When it passes by value, it places a complete
  17796.          copy of the parameter on the stack. Consult your language
  17797.          documentation for the details of when the language passes by value
  17798.          or reference. (In C, the default is by value except for arrays.)
  17799.  
  17800.       3. Observe the language naming convention.
  17801.  
  17802.       Microsoft BASIC, FORTRAN, and Pascal output symbolic names in uppercase
  17803.       characters, which is also the default behavior of the assembler. Each
  17804.       language recognizes a different number of characters in a name. For
  17805.       example, BASIC recognizes up to 40 characters of a name, whereas the
  17806.       assembler recognizes only the first 31.
  17807.  
  17808.    In the following example program, QuickBASIC 4.0 calls an assembly
  17809.    procedure that calculates "A x 2B," where A and B are the first and second
  17810.    parameters, respectively. The calculation is performed by shifting the
  17811.    bits in A to the left, B times. (Note: with earlier versions of BASIC, you
  17812.    need to rewrite the example so that it calls a subprogram, not a
  17813.    function.)
  17814.  
  17815.    ' BASIC program
  17816.    DEFINT A-Z
  17817.    PRINT "3 times 2 to the power of 5 is ";
  17818.    PRINT Power2(3,5)
  17819.    END
  17820.  
  17821.    To understand how to write the assembly procedure, consider how the
  17822.    parameters are placed on the stack, as illustrated in Figure A.4.
  17823.  
  17824.    ┌────────────────────────────────────────────────────────────────────────┐
  17825.    │ This figure can be found in Section A.3 of the manual                  │
  17826.    └────────────────────────────────────────────────────────────────────────┘
  17827.  
  17828.    The return address is four bytes long because procedures called from BASIC
  17829.    must be FAR. Arg 1 (parameter 1) is higher in memory than Arg 2 because
  17830.    BASIC pushes arguments (parameters) in the same order in which they
  17831.    appear. Also, each argument is passed as a two-byte offset address, the
  17832.    BASIC default.
  17833.  
  17834.    The assembly procedure can be written as follows:
  17835.  
  17836.                .MODEL      medium
  17837.                .CODE
  17838.                PUBLIC      Power2
  17839.    Power2      PROC
  17840.                push        bp              ; Entry sequence - save old BP
  17841.                mov         bpsp            ; Set stack framepointer
  17842.  
  17843.                mov         bx,[bp+8]       ; Load Arg1 into
  17844.                mov         ax,[bx]         ;   AX
  17845.                mov         bx,[bp]         ; Load Arg2 into
  17846.                mov         cx,[bx]         ;   CX
  17847.                shl         ax,cl           ; AX = AX * (2 to power of CX)
  17848.                                            ; Leave return value in AX
  17849.  
  17850.                pop         bp              ; Exit sequence - restore old BP
  17851.                ret         4               ; Return, and restore 4 bytes
  17852.    Power2      ENDP
  17853.                END
  17854.  
  17855.    Note that each parameter must be loaded in a two-step process because the
  17856.    address of each is passed rather than the value. Also, note that the stack
  17857.    is restored with the instruction ret 4, since the total size of the
  17858.    parameters is four bytes.
  17859.  
  17860.  
  17861.  A.4  Calling High-Level Languages from Assembly Language
  17862.  
  17863.    Many high-level-language routines assume that certain initialization code
  17864.    has previously been executed; you can ensure that the proper
  17865.    initialization is performed by starting in a high-level-language module,
  17866.    and then calling an assembly procedure. The assembly procedure can then
  17867.    call high-level-language routines as needed, as shown in Figure A.5.
  17868.  
  17869.    ┌────────────────────────────────────────────────────────────────────────┐
  17870.    │ This figure can be found in Section A.4 of the manual                  │
  17871.    └────────────────────────────────────────────────────────────────────────┘
  17872.  
  17873.    To execute an assembly call to a high-level language, you need to observe
  17874.    the following guidelines:
  17875.  
  17876.    1. Push each parameter onto the stack, observing the calling convention of
  17877.       the high-level language. Constants, such as offset addresses, must
  17878.       first be loaded into a register before being pushed.
  17879.  
  17880.    2. With long parameters, always push the segment or high-order portion of
  17881.       the parameter first, regardless of the calling convention.
  17882.  
  17883.    3. If you are using the BASIC/FORTRAN/Pascal calling convention with a
  17884.       function that returns a noninteger value, allocate an additional
  17885.       two-byte parameter. This additional parameter should contain the offset
  17886.       of the location where you want the value returned and must be pushed on
  17887.       the stack last.
  17888.  
  17889.    4. Execute a call. The call must be far unless the high-level-language
  17890.       routine is small model.
  17891.  
  17892.    5. If the routine used the C calling convention, after the call you must
  17893.       immediately clear the stack of parameters with the instruction add sp,
  17894.       size, where size is the total size in bytes of all parameters that were
  17895.       pushed.
  17896.  
  17897.  
  17898.  A.5  Using Full Segment Definitions
  17899.  
  17900.    If you use the simplified segment directives by themselves, you do not
  17901.    need to know the names assigned for each segment. However, if you choose
  17902.    to use full segment definitions, you should use the SEGMENT, GROUP,
  17903.    ASSUME, and ENDS directives equivalent to the simplified segment
  17904.    directives.
  17905.  
  17906.    The following example shows the C-assembly program from Section A.3,
  17907.    without the simplified segment directives:
  17908.  
  17909.    _TEXT       SEGMENT     WORD PUBLIC 'CODE'
  17910.                ASSUME      cs:_TEXT
  17911.                PUBLIC      _Power2
  17912.    _Power2     PROC
  17913.                push        bp             ; Entry sequence - save BP
  17914.                mov         bp,sp          ; Set stack frame
  17915.  
  17916.                mov         ax,[bp+4]      ; Load Arg1 into AX
  17917.                mov         cx,[bp+6]      ; Load Arg2 into CX
  17918.                shl         ax,cl          ; AX = AX * (2 to power of CX)
  17919.                                           ; Leave return value in AX
  17920.  
  17921.                pop         bp             ; Exit sequence - restore BP
  17922.                ret                        ; Return
  17923.    _Power2     ENDP
  17924.    _TEXT       ENDS
  17925.                END
  17926.  
  17927.  
  17928.  
  17929.  ────────────────────────────────────────────────────────────────────────────
  17930.  Appendix B:  Using Assembler Options with QCL
  17931.  
  17932.  
  17933.    You can use the QCL driver for both compiling and assembling. The driver
  17934.    compiles .C files and assembles .ASM files. Unless the /c option is given,
  17935.    the QCL driver then links together all resulting .OBJ files, as well as
  17936.    any .OBJ files specified on the command line. The default file extension
  17937.    is .OBJ.
  17938.  
  17939.    If you acquired QuickAssembler as an upgrade, make sure you use the
  17940.    version of QCL that came with the QuickAssembler package. This driver
  17941.    program is an updated and expanded version, and it supports assembly
  17942.    options in addition to all the compile options listed in the QuickC Tool
  17943.    Kit.
  17944.  
  17945.    The following options may affect work with .ASM files, but are not
  17946.    described here because they work precisely the same way as described in
  17947.    the QuickC Tool Kit:
  17948.  
  17949.    Option              Action
  17950.    ──────────────────────────────────────────────────────────────────────────
  17951.    /help               Print help listing for QCL
  17952.  
  17953.    /link flags         Specify linker flags
  17954.  
  17955.    /Fefile             Specify output file
  17956.  
  17957.    /Fofile             Name object file
  17958.  
  17959.    /Z{d|i}             Generate debugging information.
  17960.  
  17961.  
  17962.    The /c, /D, and /W options are documented in the QuickC Tool Kit, but are
  17963.    also documented here because their meaning and usage change somewhat for
  17964.    assembly-language files.
  17965.  
  17966.    In addition to the linker options documented in the QuickC Tool Kit, QCL
  17967.    supports one other option, /TINY. This option causes the linker to output
  17968.    a .COM file, if possible. The linker can only create a .COM file if the
  17969.    program is entirely written in assembly language, and all the modules
  17970.    observe the rules for the .COM format. (The easiest way to do this is to
  17971.    use tiny memory model as described in Chapter 5.) The following example
  17972.    generates a .COM file:
  17973.  
  17974.    QCL /AT TINYPROG.ASM /link /TINY
  17975.  
  17976.    The /AT option causes the assembler to check the assembly code for
  17977.    adherence to the .COM format. The /TINY linker option causes the linker to
  17978.    generate a .COM file.
  17979.  
  17980.    The QuickAssembler version of QCL supports the following options in
  17981.    addition to the ones supported for use with C-language modules:
  17982.  
  17983.    Option              Action
  17984.    ──────────────────────────────────────────────────────────────────────────
  17985.    /a                  Writes segments in alphabetical order
  17986.  
  17987.    /AT                 Requires program to use tiny memory model; gives error
  17988.                        messages for code that violates requirements of .COM
  17989.                        format
  17990.  
  17991.    /C{l|u|x}           Determines case sensitivity (l=preserve case,
  17992.                        u=convert to upper, x=preserve case of external and
  17993.                        public symbols)
  17994.  
  17995.    /D                  Defines symbols
  17996.  
  17997.    /Ez                 Displays error lines on screen
  17998.  
  17999.    /Flfile             Generates an assembly-listing file with given file
  18000.                        name
  18001.  
  18002.    /FPi                Creates code for emulated floating-point instructions
  18003.  
  18004.    /l                  Generates an assembly-listing file
  18005.  
  18006.    /P1                 Enables one-pass assembly
  18007.  
  18008.    /s                  Writes segments in source-code order (reverses effect
  18009.                        of /a)
  18010.  
  18011.    /Sa                 Lists all lines of macro expansions (assumes /Flfile
  18012.                        or /l is given)
  18013.  
  18014.    /Sd                 Adds pass 1 information to listing (assumes /Flfile or
  18015.                        /l is given)
  18016.  
  18017.    /Se                 Creates editor-oriented listing file; the resulting
  18018.                        listing has no page breaks or page headings (assumes
  18019.                        /Flfile or /l is given)
  18020.  
  18021.    /Sn                 Suppresses symbol-table in listing (assumes /Flfile or
  18022.                        /l is given)
  18023.  
  18024.    /Sq                 Generates an editor-based listing file with a
  18025.                        source-line index at the end (assumes Flfile or /l is
  18026.                        given)
  18027.  
  18028.    /Sx                 Suppresses listing of false conditionals (assumes
  18029.                        Flfile or /l is given)
  18030.  
  18031.    /t                  Suppresses messages if assembly is successful
  18032.  
  18033.    /v                  Displays extra statistics during assembly
  18034.  
  18035.    /w                  Equivalent to /W0
  18036.  
  18037.    /W{0|1|2}           Sets warning-message level
  18038.  
  18039.  
  18040.  
  18041.  B.1  Specifying the Segment-Order Method
  18042.  
  18043.    Syntax
  18044.  
  18045.    /s           Default
  18046.    /a
  18047.  
  18048.    The /a option directs QuickAssembler to place the assembled segments in
  18049.    alphabetical order before copying them to the object file. The /s option
  18050.    directs the assembler to write segments in the order in which they appear
  18051.    in the source code.
  18052.  
  18053.    Source-code order is the default. If no option is given, QuickAssembler
  18054.    copies the segments in the order encountered in the source file. The /s
  18055.    option is provided for compatibility with the XENIX(R) operating system
  18056.    and for overriding a default option in the QuickAssembler environment
  18057.    variable.
  18058.  
  18059.    ──────────────────────────────────────────────────────────────────────────
  18060.    NOTE  Some previous versions of the IBM Macro Assembler ordered segments
  18061.    alphabetically by default. Listings in some books and magazines have been
  18062.    written with these early versions in mind. If you have trouble assembling
  18063.    and linking a listing taken from a book or magazine, try using the /a
  18064.    option.
  18065.    ──────────────────────────────────────────────────────────────────────────
  18066.  
  18067.    The order in which segments are written to the object file is only one
  18068.    factor in determining the order in which they will appear in the
  18069.    executable file. The significance of segment order and ways to control it
  18070.    are discussed in Sections 5.2.1, "Setting the Segment-Order Method" and
  18071.    5.2.2.2, "Defining Segment Combinations with Combine Type."
  18072.  
  18073.    Example
  18074.  
  18075.    QCL /a file.asm
  18076.  
  18077.    The example above creates an object file, FILE.OBJ, whose segments are
  18078.    arranged in alphabetical order. If the /s option were used instead, or if
  18079.    no option were specified, the segments would be arranged in sequential
  18080.    order.
  18081.  
  18082.  
  18083.  B.2  Checking Code for Tiny Model
  18084.  
  18085.    Syntax
  18086.  
  18087.    /AT
  18088.  
  18089.    The /AT option causes the assembler to enforce the requirements of .COM
  18090.    format. If the .MODEL directive is used, /AT generates an error unless the
  18091.    directive specifies tiny memory model. If the .MODEL directive is not
  18092.    used, the /AT option generates an error if any program-defined segments
  18093.    are referenced (since these references violate conditions of .COM format).
  18094.  
  18095.    The use of /AT alone does not generate a .COM file. You must also use the
  18096.    /TINY linker option, as in the following example:
  18097.  
  18098.    QCL /AT TINYPROG.ASM /link /TINY
  18099.  
  18100.  
  18101.  B.3  Selecting Case Sensitivity
  18102.  
  18103.    Syntax
  18104.  
  18105.    /Cu          Default
  18106.    /Cl
  18107.    /Cx
  18108.  
  18109.    The /Cl option directs the assembler to make all names case sensitive. The
  18110.    /Cx option directs the assembler to make public and external names case
  18111.    sensitive. The /Cu option directs the assembler to convert all names to
  18112.    uppercase.
  18113.  
  18114.    By default, QuickAssembler converts all names to uppercase (/Cu).
  18115.  
  18116.    If case sensitivity is turned on, all names that have the same spelling
  18117.    but use letters of different cases are considered distinct. For example,
  18118.    with the /Cl option, DATA and data are different. They would also be
  18119.    different with the /Cx option if they were declared external or public.
  18120.    Public and external names include any label, variable, or symbol names
  18121.    defined by using the EXTRN, PUBLIC, or COMM directives (see Chapter 8,
  18122.    "Creating Programs from Multiple Modules").
  18123.  
  18124.    If you use the /Zi or /Zd option (these cause QCL to include debugging
  18125.    information), the /Cx, /Cl, and /Cu options affect the case of the
  18126.    symbolic data that will be available to a symbolic debugger.
  18127.  
  18128.    The /Cl and /Cx options are typically used when object modules created
  18129.    with QuickAssembler are to be linked with object modules created by a
  18130.    case-sensitive compiler such as the Microsoft C compiler. If case
  18131.    sensitivity is important, you should also use the linker /NOI option.
  18132.  
  18133.    Example
  18134.  
  18135.    QCL /Cx module.asm
  18136.  
  18137.    This example shows how to use the /Cx option with QuickAssembler to
  18138.    assemble a file with case-sensitive public symbols.
  18139.  
  18140.  
  18141.  B.4  Defining Assembler Symbols
  18142.  
  18143.    Syntax
  18144.  
  18145.    /Dsymbol[[=value]]
  18146.  
  18147.    The /D option, when given with a symbol argument, directs QuickAssembler
  18148.    to define a symbol that can be used during the assembly as if it were
  18149.    defined as a text equate in the source file. Multiple symbols can be
  18150.    defined in a single command line.
  18151.  
  18152.    The value can be any text string that does not include a space, comma, or
  18153.    semicolon. If value is not given, the symbol is assigned a null string.
  18154.  
  18155.    Example
  18156.  
  18157.    QCL /Dwide /Dmode=3 file,,;
  18158.  
  18159.    This example defines the symbol wide and gives it a null value. The symbol
  18160.    could then be used in the following conditional-assembly block:
  18161.  
  18162.                IFDEF wide
  18163.                PAGE 50,132
  18164.                ENDIF
  18165.  
  18166.    When the symbol is defined in the command line, the listing file is
  18167.    formatted for a 132-column printer. When the symbol is not defined in the
  18168.    command line, the listing file is given the default width of 80 (see the
  18169.    description of the PAGE directive in Section 12.2, "Controlling Page
  18170.    Format in Listings").
  18171.  
  18172.    The example also defines the symbol mode and gives it the value 3. The
  18173.    symbol could then be used in a variety of contexts, as shown below:
  18174.  
  18175.                IF      mode LT 15         ; Use in expression
  18176.    scrmode     DB      mode               ; Initialize to mode
  18177.                ELSE
  18178.    scrmode     DB      15                 ; Initialize to 15
  18179.                ENDIF
  18180.  
  18181.  
  18182.  B.5  Displaying Error Lines on the Screen
  18183.  
  18184.    Syntax
  18185.  
  18186.    /Ez
  18187.  
  18188.    The /Ez option directs QuickAssembler to display lines containing errors
  18189.    on the screen. Normally, when the assembler encounters an error, it
  18190.    displays only an error message describing the problem. When you use the
  18191.    /Ez option in the command line, the assembler displays the source line
  18192.    that produced the error in addition to the error message. QuickAssembler
  18193.    assembles faster without the /Ez option, but you may find the convenience
  18194.    of seeing the incorrect source lines worth the slight cost in processing
  18195.    speed.
  18196.  
  18197.    Example
  18198.  
  18199.    QCL /Ez file.asm
  18200.  
  18201.  
  18202.  B.6  Creating Code for a Floating-Point Emulator
  18203.  
  18204.    Syntax
  18205.  
  18206.    /FPi 87 /FPi
  18207.  
  18208.    The /FPi and /FPi87 options control how instructions for a math
  18209.    coprocessor (such as the 8087, 80287, or 80387) are assembled. The /FPi
  18210.    option tells the assembler to generate code for a coprocessor emulator
  18211.    library. The /FPi87 option tells the assembler to generate code for a
  18212.    coprocessor. These options are different than most other QuickAssembler
  18213.    options in that the default for C files is /FPi, but the default for
  18214.    assembler files is /FPi87. They are also different in that the options
  18215.    must be specified separately for each file.
  18216.  
  18217.    An emulator library uses the instructions of a coprocessor if one is
  18218.    present; otherwise, the library executes interrupts that emulate
  18219.    coprocessor instructions. Emulator libraries are available for QuickC and
  18220.    other high-level language compilers, including Microsoft Pascal, BASIC,
  18221.    and FORTRAN compilers.
  18222.  
  18223.    With QuickAssembler, you should specify /FPi only for assembly modules
  18224.    that will be linked with a main C module, since the emulator code requires
  18225.    the start-up code generated by the C compiler. A stand-alone assembler
  18226.    program generated with /FPi will execute emulator interrupts, but the
  18227.    program will not work because the interrupts will not be initialized. If
  18228.    you are programming in the QC environment and you want the emulator
  18229.    library to be used with an assembler module, you must specify /FPi in the
  18230.    Global Custom Flags field of the Assembler Flags dialog box (reached from
  18231.    the Options menu). This will affect all assembly modules in the program
  18232.    list.
  18233.  
  18234.    To the applications programmer, writing code for the emulator is like
  18235.    writing code for a coprocessor. The instruction sets are the same (except
  18236.    as noted in Chapter 17, "Calculating with a Math Coprocessor"). However,
  18237.    at run time the coprocessor instructions are used only if there is a
  18238.    coprocessor available on the machine. If there is no coprocessor, the
  18239.    slower code from the emulator library is used instead.
  18240.  
  18241.    The /FPi87 option specifies that coprocessor instructions should be
  18242.    generated directly. It does not need to be given directly for assembly
  18243.    modules, since it is the default, but it must be specified for C modules.
  18244.    Programs that use this option can be run only on a system that has a
  18245.    coprocessor. If the program contains a main C module, it will fail with a
  18246.    warning if the system has no coprocessor. If the program is a stand-alone
  18247.    assembler program, you should write the code to check for a coprocessor
  18248.    and terminate with an error message if no coprocessor exists.
  18249.  
  18250.    Example
  18251.  
  18252.    QCL calc.c /FPi /Cx math.asm
  18253.  
  18254.    The example above assembles MATH.ASM with the /FPi option and compiles the
  18255.    C source file CALC.C. The resulting object files are then linked together
  18256.    to produce the file CALC.EXE. The C compiler generates emulator code for
  18257.    floating-point instructions. The FORTRAN, BASIC, and Pascal compilers
  18258.    generate similar code.
  18259.  
  18260.  
  18261.  B.7  Creating Listing Files
  18262.  
  18263.    Syntax
  18264.  
  18265.    /l
  18266.    /Flfile
  18267.  
  18268.    The /l option directs QuickAssembler to create a listing file. Files
  18269.    specified with this option always have the base name of the source file
  18270.    plus a .LST extension. You cannot specify any other file name. The /Fl
  18271.    option has the same purpose as /l, but lets you specify any file name as
  18272.    the listing file. The default file name is the base file name plus a .LST
  18273.    extension.
  18274.  
  18275.    Example
  18276.  
  18277.    QCL /l prog.asm
  18278.  
  18279.    This example causes the assembler to generate the file PROG.LST during
  18280.    assembly.
  18281.  
  18282.  
  18283.  B.8  Enabling One-Pass Assembly
  18284.  
  18285.    Syntax
  18286.  
  18287.    /P1
  18288.  
  18289.    The /P1 option causes the assembler to attempt translation of source code
  18290.    in one pass. If successful, the translation is significantly faster than
  18291.    the default two-pass assembly. Assembly modules cannot be successfully
  18292.    assembled with this option if they contain conditional-assembly directives
  18293.    that make references to pass 1 or pass 2.
  18294.  
  18295.    ──────────────────────────────────────────────────────────────────────────
  18296.    NOTE  One-pass assembly is not compatible with the generation of listing
  18297.    files or the /a option for specifying alphabetical segment order.
  18298.    ──────────────────────────────────────────────────────────────────────────
  18299.  
  18300.    If the assembler generates a message reporting that one-pass assembly is
  18301.    not possible, simply assemble the file again without using this option.
  18302.  
  18303.    Example
  18304.  
  18305.    QCL /P1 file.asm
  18306.  
  18307.  
  18308.  B.9  Listing All Lines of Macro Expansions
  18309.  
  18310.    Syntax
  18311.  
  18312.    /Sa
  18313.  
  18314.    The /Sa option causes the listing file to contain all statements generated
  18315.    by the assembler. It overrides directives that limit listings such as
  18316.    .XLIST, .XALL, and .SFCOND. It forces display of all statements generated
  18317.    automatically by simplified segment directives and the extended PROC
  18318.    syntax. The /Sa option has no effect unless /l or /Fl is also specified.
  18319.  
  18320.    Example
  18321.  
  18322.    QCL /l /Sa file.asm
  18323.  
  18324.  
  18325.  B.10  Creating a Pass 1 Listing
  18326.  
  18327.    Syntax
  18328.  
  18329.    /Sd
  18330.  
  18331.    The /Sd option causes the listing file to contain the results of both
  18332.    assembler passes. A pass 1 listing is typically used to locate phase
  18333.    errors. Phase errors occur when the assembler makes assumptions about the
  18334.    program in pass 1 that are not valid in pass 2. The /Sd option has no
  18335.    effect unless /l or /Fl is also specified.
  18336.  
  18337.    Example
  18338.  
  18339.    QCL /l /Sd file.asm
  18340.  
  18341.  
  18342.  B.11  Specifying an Editor-Oriented Listing
  18343.  
  18344.    Syntax
  18345.  
  18346.    /Se
  18347.  
  18348.    The /Se option causes the assembler to generate the listing file in a
  18349.    format suited to text editors. This format does not contain page breaks or
  18350.    page headings. The default behavior, which is designed for files output to
  18351.    a printer, assumes a page break and heading at periodic intervals. The /Se
  18352.    option has no effect unless /l or /Fl is also specified.
  18353.  
  18354.    Example
  18355.  
  18356.    QCL /l /Se file.asm
  18357.  
  18358.  
  18359.  B.12  Suppressing Tables in the Listing File
  18360.  
  18361.    Syntax
  18362.  
  18363.    /Sn
  18364.  
  18365.    The /Sn option tells the assembler to omit all tables from the end of the
  18366.    listing file. If this option is not chosen, QuickAssembler includes tables
  18367.    of macros, structures, records, segments and groups, and symbols. The code
  18368.    portion of the listing file is not changed by the /Sn option. The /Sn
  18369.    option has no effect unless /l or /Fl is also specified.
  18370.  
  18371.    Example
  18372.  
  18373.    QCL /l /Sn file.asm
  18374.  
  18375.  
  18376.  B.13  Adding a Line-Number Index to the Listing
  18377.  
  18378.    Syntax
  18379.  
  18380.    /Sq
  18381.  
  18382.    The /Sq option generates an editor-based listing file just as the /Se
  18383.    option does, but it also adds a source-line index to the end of the
  18384.    listing file. This index contains pairs of corresponding line numbers for
  18385.    the listing file and appropriate source files. The QuickC/QuickAssembler
  18386.    environment uses this information to let you move from a source file to
  18387.    the corresponding position in a listing file.
  18388.  
  18389.    When you create a listing file from within the QuickC/QuickAssembler
  18390.    environment, QC.EXE automatically passes this option to the assembler. The
  18391.    /Sq option has no effect unless /l or /Fl is also specified.
  18392.  
  18393.    Example
  18394.  
  18395.    QCL /l /Sq file.asm
  18396.  
  18397.  
  18398.  B.14  Listing False Conditionals
  18399.  
  18400.    Syntax
  18401.  
  18402.    /Sx
  18403.  
  18404.    The /Sx option directs QuickAssembler to copy to the assembly listing all
  18405.    statements forming the body of conditional-assembly blocks whose condition
  18406.    is false. If you do not give the /Sx option in the command line,
  18407.    QuickAssembler suppresses all such statements. The /Sx option lets you
  18408.    display conditionals that do not generate code. Conditional-assembly
  18409.    directives are explained in Chapter 12, "Controlling Assembly Output."
  18410.  
  18411.    The .LFCOND, .SFCOND, and .TFCOND directives can override the effect of
  18412.    the /Sx option, as described in Section 12.3.2, "Controlling Listing of
  18413.    Conditional Blocks." The /Sx option does not affect the assembly listing
  18414.    unless you direct the assembler to create an assembly-listing file.
  18415.  
  18416.    Example
  18417.  
  18418.    QCL /Sx file,,;
  18419.  
  18420.    Listing of false conditionals is turned on when FILE.ASM is assembled.
  18421.    Directives in the source file can override the /Sx option to change the
  18422.    status of false-conditional listing.
  18423.  
  18424.  
  18425.  B.15  Controlling Display of Assembly Statistics
  18426.  
  18427.    Syntax
  18428.  
  18429.    /v
  18430.    /t
  18431.  
  18432.    The /v and /t options specify the level of information displayed to the
  18433.    screen at the end of assembly (/v is a mnemonic for verbose; /t is a
  18434.    mnemonic for terse).
  18435.  
  18436.    If neither option is given, QuickAssembler outputs a line telling the
  18437.    amount of symbol space free and the number of warnings and errors.
  18438.  
  18439.    If the /v option is given, QuickAssembler also reports the number of lines
  18440.    and symbols processed.
  18441.  
  18442.    If the /t option is given, QuickAssembler does not output anything to the
  18443.    screen unless errors are encountered. This option may be useful in batch
  18444.    or make files if you do not want the output cluttered with unnecessary
  18445.    messages.
  18446.  
  18447.    If errors are encountered, they will be displayed whether these options
  18448.    are given or not.
  18449.  
  18450.  
  18451.  B.16  Setting the Warning Level
  18452.  
  18453.    Syntax
  18454.  
  18455.    /W{0 | 1 | 2}
  18456.    /w
  18457.  
  18458.    The /W option sets the assembler warning level. QuickAssembler gives
  18459.    warning messages for assembly statements that are ambiguous or
  18460.    questionable but not necessarily illegal. Some programmers purposely use
  18461.    practices that generate warnings. By setting the appropriate warning
  18462.    level, they can turn off warnings if they are aware of the problem and do
  18463.    not wish to take action to remedy it. The /w option is equivalent to /W0.
  18464.  
  18465.    QuickAssembler has three levels of errors, as shown in Table B.1.
  18466.  
  18467.    Table B.1 Warning Levels
  18468.  
  18469.    Level           Type            Description
  18470.    ──────────────────────────────────────────────────────────────────────────
  18471.    0               Severe errors   Illegal statements
  18472.  
  18473.    1               Serious         Ambiguous statements or questionable
  18474.                    warnings        programming practices
  18475.  
  18476.    2               Advisory        Statements that may produce inefficient
  18477.                    warnings        code
  18478.  
  18479.    ──────────────────────────────────────────────────────────────────────────
  18480.  
  18481.  
  18482.    The default warning level is 1. A higher warning level includes all of the
  18483.    messages reported by a lower level. Level 2 includes severe errors,
  18484.    serious warnings, and advisory warnings. If severe errors are encountered,
  18485.    no object file is produced.
  18486.  
  18487.    Warning level 0 reports error messages in the range 1000-2999. Warning
  18488.    level 1 reports warning and error messages in the ranges 1000-2999 and
  18489.    4000-4999. Warning level 2 reports all warning and error messages,
  18490.    including those numbered 5000 and above.
  18491.  
  18492.  
  18493.  
  18494.  ────────────────────────────────────────────────────────────────────────────
  18495.  Appendix C:  Reading Assembly Listings
  18496.  
  18497.  
  18498.    QuickAssembler creates an assembly listing of your source file whenever
  18499.    you give an assembly-listing option on the QCL command line or select a
  18500.    listing file option in the Assembler Flags dialog box. The assembly
  18501.    listing contains both the statements in the source file and the object
  18502.    code (if any) generated for each statement. The listing also shows the
  18503.    names and values of all labels, variables, and symbols in your source
  18504.    file.
  18505.  
  18506.    The assembler creates tables for macros, structures, records, segments,
  18507.    groups, and other symbols. These tables are placed at the end of the
  18508.    assembly listing (unless you suppress them with the QCL /Sn option).
  18509.    QuickAssembler lists only the types of symbols encountered in the program.
  18510.    All symbol names will be shown in uppercase letters unless you choose
  18511.    Preserve Case or Preserve Extrn from the Assembler Flags dialog box or use
  18512.    a QCL option (/Cx or /Cl) that supports case sensitivity.
  18513.  
  18514.  
  18515.  C.1  Reading Code in a Listing
  18516.  
  18517.    The assembler lists the code generated from the statements of a source
  18518.    file. Each line has the syntax shown below:
  18519.  
  18520.    offset [[code]] statement
  18521.  
  18522.    The offset is the offset from the beginning of the current segment to the
  18523.    code. If the statement generates code or data, code shows the numeric
  18524.    value in hexadecimal if the value is known at assembly time. If the value
  18525.    is calculated at run time, the assembler indicates what action is
  18526.    necessary to compute the value. The statement is the source statement
  18527.    shown exactly as it appears in the source file, or as expanded by a macro.
  18528.  
  18529.    If any errors occur during assembly, each error message and error number
  18530.    will appear directly below the statement where the error occurred. An
  18531.    example of an error line and message is shown below:
  18532.  
  18533.    0012  E8 001C R                            call    doit
  18534.    test.ASM(46): error A2071: Forward needs override or FAR
  18535.  
  18536.    The assembler uses the symbols and abbreviations in Table C.1 to indicate
  18537.    addresses that need to be resolved by the linker or values that were
  18538.    generated in a special way.
  18539.  
  18540.    Table C.1 Symbols and Abbreviations in Listings
  18541.  
  18542.    Character          Meaning
  18543.    ──────────────────────────────────────────────────────────────────────────
  18544.    R                  Relocatable address (linker must resolve)
  18545.  
  18546.    E                  External address (linker must resolve)
  18547.  
  18548.    ----               Segment/group address (linker must resolve)
  18549.  
  18550.    =                  EQU or equal-sign (=) directive
  18551.  
  18552.    nn:                Segment override in statement
  18553.  
  18554.    nn/                REP or LOCK prefix instruction
  18555.  
  18556.    nn[xx]             DUP expression: nn copies of the value xx
  18557.  
  18558.    n                  Macro-expansion nesting level (+ if more than nine)
  18559.  
  18560.    C                  Line from include file
  18561.  
  18562.    ──────────────────────────────────────────────────────────────────────────
  18563.  
  18564.  
  18565.    Example
  18566.  
  18567.    The sample listing shown in this section is produced using the /Se option,
  18568.    which produces an editor-oriented listing. The QuickC/QuickAssembler
  18569.    environment always produces this kind of listing. The editor-oriented
  18570.    environment produces no page headings and is thus ideal for viewing within
  18571.    the environment or another editor. If you are using QCL to generate a
  18572.    listing file that you intend to print, you may want to generate a
  18573.    printer-oriented listing file by giving the /Sp option:
  18574.  
  18575.    QCL /l /Sp listdemo.asm
  18576.  
  18577.    The code portion of the resulting listing is shown below. The tables
  18578.    normally seen at the end of the listing are explained later, in Sections
  18579.    C.2-C.7.
  18580.  
  18581.    Microsoft(R) QuickC with QuickAssembler Version 2.01 Listing features demo
  18582.  
  18583.                                            PAGE    65,132
  18584.                                            TITLE   Listing features  demo
  18585.                                 C          INCLUDE dos.mac
  18586.                                 C  StrAlloc    MACRO   name,text
  18587.                                 C  name        DB      &text
  18588.                                 C              DB      13d,10d
  18589.                                 C  l&name      EQU     $-name
  18590.                                 C              ENDM
  18591.  
  18592.    = 0080                         larg    EQU     80h
  18593.  
  18594.                                           DOSSEG
  18595.                                           .MODEL  small
  18596.  
  18597.    0100                                   .STACK  256
  18598.  
  18599.                                   color   RECORD  b:1,r:3=1,i:1=1,f:3=7
  18600.  
  18601.                                   date    STRUC
  18602.    0000  05                       month   DB      5
  18603.    0001  07                       day     DB      7
  18604.    0002  07C3                     year    DW      1987
  18605.    0004                           date    ENDS
  18606.  
  18607.    0000                                   .DATA
  18608.    0000  1F                       text    color   <>
  18609.    0001  09                       today   date    <9,22,1987>
  18610.    0002  16
  18611.    0003  07C3
  18612.  
  18613.    0005  0064[                    buffer  DW      100 DUP(?)
  18614.                ????
  18615.  
  18616.  
  18617.  
  18618.                                           StrAlloc ending,"Finished."
  18619.    00CD  46 69 6E 69 73 68 65  1  ending        DB      "Finished."
  18620.    00D6  0D 0A                 1              DB      13d,10d
  18621.  
  18622.    0000                                   .CODE
  18623.  
  18624.    0000  B8 ---- R                start:  mov     ax,@DATA
  18625.    0003  8E D8                            mov     ds,ax
  18626.  
  18627.    0005  B8 0063                          mov     ax,'c'
  18628.    0008  26: 8B 0E 0080                   mov     cx,es:larg
  18629.    000D  BF 0052                          mov     di,82
  18630.    0010  F2/ AE                           repne   scasb
  18631.    0012  57                               push    di
  18632.  
  18633.                                           EXTRN   work:NEAR
  18634.    0013  E8 0000 E                        call    work
  18635.  
  18636.    0016  B8 170C                          mov     ax,4C00
  18637.    listdemo.ASM(40): error A2107: Non-digit in number
  18638.    0019  CD 21                            int     21h
  18639.  
  18640.    001B                                   END     start
  18641.  
  18642.  
  18643.  C.2  Reading a Macro Table
  18644.  
  18645.    A macro table at the end of a listing file gives the names and sizes (in
  18646.    lines) of all macros called or defined in the source file. The macros
  18647.    appear in alphabetical order.
  18648.  
  18649.    Example
  18650.  
  18651.    Macros:
  18652.  
  18653.                    N a m e                 Lines
  18654.  
  18655.    STRALLOC . . . . . . . . . . . .           3
  18656.  
  18657.  
  18658.  C.3  Reading a Structure and Record Table
  18659.  
  18660.    All structures and records declared in the source file are given at the
  18661.    end of the listing file. The names are listed in alphabetical order. Each
  18662.    name is followed by the fields in the order in which they are declared.
  18663.  
  18664.    Example
  18665.  
  18666.    Structures and Records:
  18667.  
  18668.                    N a m e                 Width   # fields
  18669.                                            Shift   Width   Mask    Initial
  18670.  
  18671.    COLOR  . . . . . . . . . . . . .        0008    0004
  18672.      B  . . . . . . . . . . . . . .        0007    0001    0080    0000
  18673.      R  . . . . . . . . . . . . . .        0004    0003    0070    0010
  18674.      I  . . . . . . . . . . . . . .        0003    0001    0008    0008
  18675.      F  . . . . . . . . . . . . . .        0000    0003    0007    0007
  18676.    DATE . . . . . . . . . . . . . .        0004    0003
  18677.      MONTH  . . . . . . . . . . . .        0000
  18678.      DAY  . . . . . . . . . . . . .        0001
  18679.      YEAR . . . . . . . . . . . . .        0002
  18680.  
  18681.    The first row of headings only applies to the record or structure itself.
  18682.    For a record, the "Width" column shows the width in bits while the "#
  18683.    fields" column tells the total number of fields.
  18684.  
  18685.    The second row of headings applies only to fields of the record or
  18686.    structure. For records, the "Shift" column lists the offset (in bits) from
  18687.    the low-order bit of the record to the low-order bit in the field. The
  18688.    "Width" column lists the number of bits in the field. The "Mask" column
  18689.    lists the maximum value of the field, expressed in hexadecimal. The
  18690.    "Initial" column lists the initial value of the field, if any. For each
  18691.    field, the table shows the mask and initial values as if they were placed
  18692.    in the record and all other fields were set to 0.
  18693.  
  18694.    For a structure, the "Width" column lists the size of the structure in
  18695.    bytes. The "# fields" column lists the number of fields in the structure.
  18696.    Both values are in hexadecimal.
  18697.  
  18698.    For structure fields, the "Shift" column lists the offset in bytes from
  18699.    the beginning of the structure to the field. This value is in hexadecimal.
  18700.    The other columns are not used.
  18701.  
  18702.  
  18703.  C.4  Reading a Segment and Group Table
  18704.  
  18705.    Segments and groups used in the source file are listed at the end of the
  18706.    program with their size, align type, combine type, and class. If you used
  18707.    simplified segment directives in the source file, the actual segment names
  18708.    generated by QuickAssembler will be listed in the table.
  18709.  
  18710.    Example
  18711.  
  18712.    Segments and Groups:
  18713.  
  18714.                    N a m e                 Size    Align   Combine Class
  18715.  
  18716.    DGROUP . . . . . . . . . . . . .        GROUP
  18717.      _DATA  . . . . . . . . . . . .        00D8    WORD    PUBLIC  'DATA'
  18718.      STACK  . . . . . . . . . . . .        0800    PARA    STACK   'STACK'
  18719.    _TEXT  . . . . . . . . . . . . .        0018    BYTE    PUBLIC  'CODE'
  18720.  
  18721.    The "Name" column lists the names of all segments and groups. Segment and
  18722.    group names are given in alphabetical order, except that the names of
  18723.    segments belonging to a group are placed under the group name in the order
  18724.    in which they were added to the group.
  18725.  
  18726.    The "Size" column lists the byte size (in hexadecimal) of each segment.
  18727.    The size of groups is not shown.
  18728.  
  18729.    The "Align" column lists the align type of the segment.
  18730.  
  18731.    The "Combine" column lists the combine type of the segment. If no explicit
  18732.    combine type is defined for the segment, the listing shows NONE,
  18733.    representing the private combine type. If the "Align" column contains AT,
  18734.    the "Combine" column contains the hexadecimal address of the beginning of
  18735.    the segment.
  18736.  
  18737.    The "Class" column lists the class name of the segment. For a complete
  18738.    explanation of the align, combine, and class types, see Section 5.2.2,
  18739.    "Defining Full Segments."
  18740.  
  18741.  
  18742.  C.5  Reading a Symbol Table
  18743.  
  18744.    All symbols (except names for macros, structures, records, and segments)
  18745.    are listed in a symbol table at the end of the listing.
  18746.  
  18747.    Example
  18748.  
  18749.    Symbols:
  18750.  
  18751.                    N a m e              Type     Value   Attr
  18752.  
  18753.    BUFFER . . . . . . . . . . . . .     L WORD  0005    _DATA   Length = 0064
  18754.  
  18755.    ENDING . . . . . . . . . . . . .     L BYTE  00CD    _DATA
  18756.  
  18757.    LARG . . . . . . . . . . . . . .     NUMBER  0080
  18758.    LENDING  . . . . . . . . . . . .     NUMBER  000B
  18759.  
  18760.    START  . . . . . . . . . . . . .     L NEAR  0000    _TEXT
  18761.  
  18762.    TEXT . . . . . . . . . . . . . .     L BYTE  0000    _DATA
  18763.    TODAY  . . . . . . . . . . . . .     L DWORD 0001    _DATA
  18764.  
  18765.    WORK . . . . . . . . . . . . . .     L NEAR  0000    _TEXT   External
  18766.  
  18767.    @CODE  . . . . . . . . . . . . .     TEXT  _TEXT
  18768.    @CODESIZE  . . . . . . . . . . .     TEXT  0
  18769.    @DATA  . . . . . . . . . . . . .     TEXT  DGROUP
  18770.    @DATASIZE  . . . . . . . . . . .     TEXT  0
  18771.    @FARDATA . . . . . . . . . . . .     TEXT  FAR_DATA
  18772.    @FARDATA?  . . . . . . . . . . .     TEXT  FAR_BSSk
  18773.    @FILENAME  . . . . . . . . . . .     TEXT  listdemo
  18774.    @MODEL . . . . . . . . . . . . .     TEXT  1
  18775.    @VERSION . . . . . . . . . . . .     TEXT  520
  18776.  
  18777.    The "Name" column lists the names in alphabetical order. The "Type" column
  18778.    lists each symbol's type. A type is given as one of the following:
  18779.  
  18780.    Type                Definition
  18781.    ──────────────────────────────────────────────────────────────────────────
  18782.    L NEAR              A near label
  18783.  
  18784.    L FAR               A far label
  18785.  
  18786.    N PROC              A near procedure label
  18787.  
  18788.    F PROC              A far procedure label
  18789.  
  18790.    NUMBER              An absolute label
  18791.  
  18792.    ALIAS               An alias for another symbol
  18793.  
  18794.    TEXT                A text equate
  18795.  
  18796.    BYTE                One byte
  18797.  
  18798.    WORD                One word (two bytes)
  18799.  
  18800.    DWORD               Doubleword (four bytes)
  18801.  
  18802.    QWORD               Quadword (eight bytes)
  18803.  
  18804.    TBYTE               Ten bytes
  18805.  
  18806.    number              Length in bytes of a structure variable
  18807.  
  18808.  
  18809.    The length of a multiple-element variable, such as an array or string, is
  18810.    the length of a single element, not the length of the entire variable. For
  18811.    example, string variables are always shown as L BYTE.
  18812.  
  18813.    If the symbol represents an absolute value defined with an EQU or
  18814.    equal-sign (=) directive, the "Value" column shows the symbol's value. The
  18815.    value may be another symbol, a string, or a constant numeric value (in
  18816.    hexadecimal), depending on whether the type is ALIAS, TEXT, or NUMBER. If
  18817.    the symbol represents a variable, label, or procedure, the "Value" column
  18818.    shows the symbol's hexadecimal offset from the beginning of the segment in
  18819.    which it is defined.
  18820.  
  18821.    The "Attr" column shows the attributes of the symbol. The attributes
  18822.    include the name of the segment (if any) in which the symbol is defined,
  18823.    the scope of the symbol, and the code length. A symbol's scope is given
  18824.    only if the symbol is defined using the EXTRN and PUBLIC directives. The
  18825.    scope can be external, global, or communal. The code length (in
  18826.    hexadecimal) is given only for procedures. The "Attr" column is blank if
  18827.    the symbol has no attribute.
  18828.  
  18829.    The text equates shown at the end of the sample table are the ones defined
  18830.    automatically when you use simplified segment directives (see Section
  18831.    5.1.1, "Understanding Memory Models").
  18832.  
  18833.  
  18834.  C.6  Reading Assembly Statistics
  18835.  
  18836.    Data on the assembly, including the number of lines and symbols processed
  18837.    and the errors or warnings encountered, is shown at the end of the
  18838.    listing.
  18839.  
  18840.    Example
  18841.  
  18842.    48 Source  Lines
  18843.         52 Total   Lines
  18844.         53 Symbols
  18845.  
  18846.      45570 + 310654 Bytes symbol space free
  18847.  
  18848.          0 Warning Errors
  18849.          1 Severe  Errors
  18850.  
  18851.  
  18852.  C.7  Reading a Pass 1 Listing
  18853.  
  18854.    When you specify the /Sd option in the QCL command line or select Pass One
  18855.    Information from the Assembler Flags dialog box, the assembler puts a pass
  18856.    1 listing in the assembly-listing file. The listing file shows the results
  18857.    of both assembler passes. Pass 1 listings are useful in analyzing phase
  18858.    errors.
  18859.  
  18860.    The following example illustrates a pass 1 listing for a source file that
  18861.    assembled without error on the second pass.
  18862.  
  18863.    0017  7E 00               jle     label1
  18864.    PASS_CMP.ASM(20) : error 9 : Symbol not defined LABEL1
  18865.    0019  BB 1000             mov     bx,4096
  18866.    001C             label1:
  18867.  
  18868.    During pass 1, the JLE instruction to a forward reference produces an
  18869.    error message and the value 0 is encoded as the operand. QuickAssembler
  18870.    displays this error because it has not yet encountered the symbol label1.
  18871.  
  18872.    Later in pass 1, label1 is defined. Therefore, the assembler knows about
  18873.    label1 on pass 2 and can fix the pass 1 error. The pass 2 listing is shown
  18874.    below:
  18875.  
  18876.    0017  7E 03               jle     label1
  18877.    0019  BB 1000             mov     bx,4096
  18878.    001C             label1:
  18879.  
  18880.    The operand for the JLE instruction is now coded as 3 instead of 0 to
  18881.    indicate that the distance of the jump to label1 is three bytes.
  18882.  
  18883.    Since QuickAssembler generated the same number of bytes for both passes,
  18884.    there was no error. Phase errors occur if the assembler makes an
  18885.    assumption on pass 1 that it cannot change on pass 2. If you get a phase
  18886.    error, you can examine the pass 1 listing to see what assumptions the
  18887.    assembler made.
  18888.  
  18889.  
  18890.  
  18891.  ═══════════════════════════════════════════════════════════════════════════
  18892.  Index
  18893.  
  18894.  
  18895.  Symbols
  18896.  
  18897.  (brackets)
  18898.    with arrays
  18899.    index operator
  18900.    with registers
  18901.  + (plus sign), to separate registers
  18902.  _ (underscore)
  18903.  
  18904.  Numbers
  18905.  
  18906.  10-byte temporary-real format
  18907.  .186 directive
  18908.  .286 directive
  18909.  .287 directive
  18910.  .8086 directive
  18911.  8086-family processors
  18912.    assembly language
  18913.    calculating physical addresses (figure)
  18914.    flags (figure)
  18915.    instructions
  18916.    registers (figure)
  18917.  .8087 directive
  18918.  8087-family registers, modifying
  18919.  
  18920.  A
  18921.  
  18922.  /a option
  18923.  AAA instruction
  18924.  AAD instruction
  18925.  AAM instruction
  18926.  AAS instruction
  18927.  ABS type
  18928.  Absolute segments
  18929.  Accumulator
  18930.  ADC instruction
  18931.  ADD instruction
  18932.  Adding
  18933.  Addressing modes
  18934.    contrasted with C
  18935.    defined
  18936.    direct memory
  18937.    immediate
  18938.    indirect memory
  18939.    listed
  18940.    register
  18941.  Advisor, Quick
  18942.  Advisory warnings
  18943.  AH register
  18944.  AL register
  18945.  Aliases
  18946.  ALIGN directive
  18947.  Align type
  18948.  Alignment, of segments
  18949.  .ALPHA directive
  18950.  & (ampersand), operator
  18951.  Ampersand (&), operator
  18952.  AND instruction
  18953.  AND operator
  18954.  \la (angle brackets), operator
  18955.  Angle brackets (\la), operator
  18956.  Animate command
  18957.  Arguments
  18958.    macros
  18959.    passing on stack
  18960.    repeat blocks
  18961.  Arithmetic operators (table)
  18962.  Arrays
  18963.    accessing elements of
  18964.    boundary checking
  18965.    defining
  18966.    specifying elements
  18967.  ASCII character set
  18968.    converting numerals to face value
  18969.    name for unpacked BCD numbers
  18970.  Assembler display mode
  18971.  Assembler Flags dialog box (figure)
  18972.  Assembler options, summary
  18973.  Assembly
  18974.    calling from C
  18975.    parameters, accessing
  18976.    passing by
  18977.      near reference
  18978.      value
  18979.    warning levels (table)
  18980.  Assembly listing
  18981.    addresses
  18982.    false conditionals
  18983.    macros
  18984.    page breaks
  18985.    page length
  18986.    page width
  18987.    reading
  18988.    subtitle
  18989.    suppressing
  18990.    title
  18991.  Assembly-language books
  18992.  ASSUME directive
  18993.  (at sign)
  18994.    symbol names, used in
  18995.  /AT option
  18996.  AT combine type
  18997.  Attributes of variables
  18998.  Auto display mode
  18999.  Automatic variables
  19000.  Auxiliary-carry flag
  19001.  AX register
  19002.  
  19003.  B
  19004.  
  19005.  Base register
  19006.  Based operands
  19007.  Based-indexed operands
  19008.  BASIC
  19009.    calling convention
  19010.    for loops
  19011.    nestinglevel
  19012.    ON GOTO statements
  19013.    stack
  19014.      frame (figure)
  19015.      long return values (figure)
  19016.  BCD (binary coded decimal) numbers
  19017.    calculations with
  19018.    constants
  19019.    defining of
  19020.    transfer instructions (list)
  19021.    variables initialized
  19022.  BH register
  19023.  Binary integers, transfer instructions (list)
  19024.  Binary radix
  19025.  Binary to decimal conversion
  19026.  BIOS functions
  19027.    calling with interrupts
  19028.    on-line help
  19029.  Bit fields
  19030.  Bit mask
  19031.  Bits, rotating and shifting (figure)
  19032.  Bitwise operators
  19033.  BL register
  19034.  Boolean bit operations
  19035.  BOUND instruction
  19036.  Boundary-checking array
  19037.  BP register
  19038.  Brackets ()
  19039.    with arrays
  19040.    index operator
  19041.    with registers
  19042.  Buffers
  19043.  Bugs, reporting
  19044.  Building programs
  19045.    within environment
  19046.    QCL driver
  19047.  BY memory operator
  19048.  BYTE align type
  19049.  BYTE type specifier
  19050.  
  19051.  C
  19052.  
  19053.  C compiler
  19054.  C display mode
  19055.  C language
  19056.    assembly call (figure)
  19057.    calling convention
  19058.    if statement
  19059.    interfacing with
  19060.    loops
  19061.    memory models and
  19062.    nestinglevel value
  19063.    passing by value
  19064.    return value
  19065.    stack frame (figure)
  19066.    switch statements
  19067.  C register variables
  19068.  CALL instruction
  19069.  Call tables
  19070.  Calling convention
  19071.  Calls command
  19072.  Carry flag
  19073.  Case sensitivity
  19074.    compilers
  19075.    lack of
  19076.    options
  19077.    preserving
  19078.  CATSTR directive
  19079.  CBW instruction
  19080.  CH register
  19081.  Character constant
  19082.  Character set
  19083.  /Cl option
  19084.  /Cl option
  19085.  CL register
  19086.    defined
  19087.    use in shifting bits
  19088.  Class type
  19089.  Classical-stack operands, coprocessor
  19090.  CLC instruction
  19091.  CLD instruction
  19092.  CLI instruction
  19093.  CMP instruction
  19094.  CMPS instruction
  19095.  .CODE directive
  19096.  CODE class name
  19097.  Code equate
  19098.  Code Segment register
  19099.  Code segments
  19100.    developing programs with
  19101.    initializing
  19102.  (colon), operator
  19103.    definition
  19104.  (colon), operator
  19105.    in Debug expressions
  19106.  .COM file, assembling
  19107.  .COM format
  19108.    debugging
  19109.    example
  19110.    with full segment definitions
  19111.    initializing
  19112.    with linker
  19113.    restrictions on
  19114.    tiny memory model
  19115.  Combine type
  19116.  COMENT object record
  19117.  COMM directive
  19118.  Command line, QC
  19119.  COMMENT directive
  19120.  COMMON combine type
  19121.  Communal symbols
  19122.  Compact memory model
  19123.  Compare instructions
  19124.  Comparing
  19125.    register to zero
  19126.    strings
  19127.  Concatenating strings
  19128.  Conditional assembly
  19129.  Conditional directives
  19130.    assembly directives
  19131.    assembly passes
  19132.    error directives
  19133.    macro arguments
  19134.    nesting
  19135.    operators
  19136.    symbol definition
  19137.    value of true and false
  19138.  Conditional-error directives (table)
  19139.  Conditional-jump instructions
  19140.    based on flag status (table)
  19141.    defined
  19142.    logic
  19143.    used after Compare (table)
  19144.  .CONST directive
  19145.  Constants
  19146.    as direct memory operands
  19147.    integer
  19148.    loading instructions (list)
  19149.    multiplying and dividing by
  19150.    packed binary coded decimal
  19151.    real number
  19152.    string
  19153.    use of
  19154.  Control data, coprocessor
  19155.  Control registers, coprocessor (figure)
  19156.  Control-flag settings (table)
  19157.  Control-flow instructions
  19158.  Controlling program flow
  19159.  Converting
  19160.    binary to decimal
  19161.    data sizes
  19162.  Coprocessors
  19163.    architecture
  19164.    control data
  19165.    control flags (figure)
  19166.    control instructions (list)
  19167.    control registers (figure)
  19168.    data registers (figure)
  19169.    directives (list)
  19170.    emulator
  19171.    loading data
  19172.    loading pi
  19173.    no-wait instructions
  19174.    operand forms (table)
  19175.    storing data
  19176.  Copying data
  19177.  Count register
  19178.  Cpu equate
  19179.  CS register
  19180.  /Cu option
  19181.  Current-line highlighting
  19182.  Custom flags
  19183.  Customer support
  19184.  CWD instruction
  19185.  /Cx option
  19186.  /Cx option
  19187.  CX register
  19188.  
  19189.  D
  19190.  
  19191.  D
  19192.  DAA instruction
  19193.  DAS instruction
  19194.  .DATA directive
  19195.  .DATA? directive
  19196.  Data conversion
  19197.  Data equate
  19198.  Data pointer, using far
  19199.  Data registers, coprocessor (figure)
  19200.  Data segments
  19201.    defining
  19202.    developing programs with
  19203.    initializing
  19204.    registers
  19205.  Data-definition directives
  19206.  Data-manipulation instructions
  19207.  DataSize equate
  19208.  DB directive
  19209.  .DBG files
  19210.  DD directive
  19211.  Debug expression operators
  19212.  Debug flags
  19213.  Debugging
  19214.    commands
  19215.    local variables
  19216.  DEC instruction
  19217.  Decimal conversion example
  19218.  Decimal, packed BCD numbers
  19219.  Decimal radix
  19220.  Declaring
  19221.    far pointers
  19222.    strings
  19223.  Decrementing
  19224.  Defaults
  19225.    file extension
  19226.    QCL driver
  19227.    radix
  19228.    segment names
  19229.    segment registers
  19230.    simplified segment
  19231.    stack size
  19232.    types
  19233.  Defining symbols from command line
  19234.  Dereferencing, pointer
  19235.  Destination operand
  19236.  Destination string
  19237.  DGROUP group name
  19238.    COMM directive, with
  19239.    DOSSEG, with
  19240.    simplified segments, with
  19241.  DH register
  19242.  DI register
  19243.  DIF
  19244.  Direction flag
  19245.  Directives
  19246.    .186
  19247.    .286
  19248.    .287
  19249.    .8086
  19250.    .8087
  19251.    ALIGN
  19252.    .ALPHA
  19253.    ASSUME
  19254.    CATSTR
  19255.    .CODE
  19256.    COMM
  19257.    COMMENT
  19258.    .CONST
  19259.    .DATA
  19260.    .DATA?
  19261.    data definition (list)
  19262.    data (list)
  19263.    DB
  19264.    DD
  19265.    defined
  19266.    DOSSEG
  19267.    DQ
  19268.    DT
  19269.    DW
  19270.    ELSE
  19271.    ELSEIF
  19272.    EQU
  19273.    equal sign (=)
  19274.    .ERR
  19275.    .ERR1
  19276.    .ERR2
  19277.    .ERRB
  19278.    .ERRDEF
  19279.    .ERRDIF
  19280.    .ERRE
  19281.    .ERRIDN
  19282.    .ERRNB
  19283.    .ERRNDEF
  19284.    .ERRNZ
  19285.    EVEN
  19286.    EXITM
  19287.    EXTRN
  19288.    .FARDATA
  19289.    .FARDATA?
  19290.    full segment
  19291.    global
  19292.    GROUP
  19293.    IF
  19294.    IF1
  19295.    IF2
  19296.    IFB
  19297.    IFDEF
  19298.    IFDIF
  19299.    IFE
  19300.    IFIDN
  19301.    IFNB
  19302.    IFNDEF
  19303.    INCLUDE
  19304.    INCLUDELIB
  19305.    INSTR
  19306.    instruction set
  19307.    IRP
  19308.    IRPC
  19309.    LABEL
  19310.    .LALL
  19311.    .LFCOND
  19312.    .LIST
  19313.    LOCAL
  19314.    MACRO
  19315.    .MODEL
  19316.    .MSFLOAT
  19317.    NAME
  19318.    on-line help
  19319.    ORG
  19320.    %OUT
  19321.    PAGE
  19322.    PROC
  19323.    PUBLIC
  19324.    PURGE
  19325.    .RADIX
  19326.    RECORD
  19327.    REPT
  19328.    .SALL
  19329.    SEGMENT
  19330.    .SEQ
  19331.    .SFCOND
  19332.    simplified segment
  19333.    SIZESTR
  19334.    .STACK
  19335.    .STARTUP
  19336.    string-manipulation (list)
  19337.    STRUC
  19338.    SUBSTR
  19339.    SUBTTL
  19340.    .TFCOND
  19341.    TITLE
  19342.    .XALL
  19343.    .XLIST
  19344.  Directives
  19345.  Displacement
  19346.  Display dialog box (figure)
  19347.  Display mode
  19348.  DIV instruction
  19349.  Divide overflow interrupt
  19350.  Dividing
  19351.    by constants
  19352.    integers
  19353.  DL register
  19354.  DM
  19355.  Document conventions
  19356.  Documentation feedback card
  19357.  $ (dollar sign)
  19358.    location counter symbol
  19359.    symbol names, used in
  19360.  Dollar sign ($)
  19361.    location counter symbol
  19362.    symbol names, used in
  19363.  DOS
  19364.    returning to
  19365.    version requirements
  19366.  DOS functions
  19367.    calling with interrupts
  19368.    Exit, registers used (list)
  19369.    on-line help
  19370.    segment-order convention
  19371.    Write, registers used (list)
  19372.  /DOSSEG linker option
  19373.  DOSSEG directive
  19374.  DP
  19375.  DQ directive
  19376.  DS
  19377.  DS register
  19378.  /Dsymbol option
  19379.  DT directive
  19380.  Dummy parameters
  19381.    macros
  19382.    repeat blocks
  19383.  Dummy segment definitions
  19384.  DUP operator
  19385.  DW directive
  19386.  DW memory operator
  19387.  DWORD type specifier
  19388.  DX register
  19389.  Dynamic variables
  19390.  
  19391.  E
  19392.  
  19393.  Effective address
  19394.  Elements, array
  19395.  ELSE directive
  19396.  ELSEIF directives
  19397.  Emulator, coprocessor
  19398.  Encoded real numbers
  19399.  END directive
  19400.  ENDIF directive
  19401.  ENDM directive
  19402.  ENDP directive
  19403.  ENDS directive
  19404.  ENTER instruction
  19405.  Environment variable, INCLUDE
  19406.  EQ operator
  19407.  EQU directive
  19408.  = (equal sign), directive
  19409.  Equal sign (=), directive
  19410.  Equates
  19411.    defined
  19412.    nonredefinable
  19413.    predefined. See predefined equates
  19414.    redefinable
  19415.    string
  19416.  .ERR directive
  19417.  .ERR1 directive
  19418.  .ERR2 directive
  19419.  .ERRB directive
  19420.  .ERRDEF directive
  19421.  .ERRDIF directive
  19422.  .ERRE directive
  19423.  .ERRIDN directive
  19424.  .ERRNB directive
  19425.  .ERRNDEF directive
  19426.  .ERRNZ directive
  19427.  Error lines, displaying
  19428.  ES register
  19429.  ESC instruction
  19430.  EVEN directive
  19431.  ! (exclamation point), operator
  19432.  Exclamation point (!), operator
  19433.  Execution, tracing
  19434.  Exit function, DOS
  19435.  Exiting a program
  19436.  EXITM directive
  19437.  Exponent, part of real-number constant
  19438.  Exponentiation, with 8087-family coprocessors
  19439.  Expression operator (%)
  19440.  Expressions
  19441.    in Debug commands
  19442.    defined
  19443.  External names
  19444.  External symbols
  19445.  Extra segment
  19446.  EXTRN directive
  19447.  /Ez option
  19448.  
  19449.  F
  19450.  
  19451.  F2XM1 instruction
  19452.  FABS instruction
  19453.  FADD instruction
  19454.  FADDP instruction
  19455.  False conditionals, listing
  19456.  Far data pointers
  19457.    decimal conversion with
  19458.    loading
  19459.  FAR type specifier
  19460.  .FARDATA? directive
  19461.  .FARDATA directive
  19462.  Fardata equate
  19463.  Fardata? equate
  19464.  farStack
  19465.  farStack keyword
  19466.  Fatal errors
  19467.  FBLD instruction
  19468.  FBSTP instruction
  19469.  FCHS instruction
  19470.  FCOM instruction
  19471.  FCOMP instruction
  19472.  FCOMPP instruction
  19473.  FDIV instruction
  19474.  FDIVP instruction
  19475.  FDIVR instruction
  19476.  FDIVRP instruction
  19477.  FIADD instruction
  19478.  FICOM instruction
  19479.  FICOMP instruction
  19480.  FIDIV instruction
  19481.  FIDIVR instruction
  19482.  Fields
  19483.    assembler statements
  19484.    bit
  19485.    records
  19486.    structures
  19487.  File extensions, default
  19488.  File menu, defaults
  19489.  Filename equate
  19490.  Files
  19491.    .COM
  19492.    .DBG
  19493.    include
  19494.    listing
  19495.    specifications
  19496.  FIMUL instruction
  19497.  Finishing execution
  19498.  FINIT instruction
  19499.  First-in-first-out (FIFO)
  19500.  FIST instruction
  19501.  FISTP instruction
  19502.  FISUB instruction
  19503.  FISUBR instruction
  19504.  /Fl option
  19505.  Flags
  19506.    8086-family processors (figure)
  19507.    altering within environment
  19508.    build
  19509.    control, settings after compare or test (table)
  19510.    coprocessor, processor control (figure)
  19511.    loading and storing
  19512.    register, summary (table)
  19513.  FLD instruction
  19514.  FLD1 instruction
  19515.  FLDCW instruction
  19516.  FLDL2E instruction
  19517.  FLDL2T instruction
  19518.  FLDLG2 instruction
  19519.  FLDLN2 instruction
  19520.  FLDPI instruction
  19521.  FLDZ instruction
  19522.  Floating-point numbers
  19523.  FMUL instruction
  19524.  FMULP instruction
  19525.  For loops, emulating high-level-language statement
  19526.  FORTRAN
  19527.    compiler
  19528.    do loops, emulating
  19529.    nestinglevel
  19530.    return value (figure)
  19531.  Forward references
  19532.    defined
  19533.    during a pass
  19534.    labels
  19535.    variables
  19536.  FPATAN instruction
  19537.  /FPi option
  19538.  FPREM instruction
  19539.  FPTAN instruction
  19540.  Fraction
  19541.  Framepointer
  19542.  FRNDINT instruction
  19543.  FSCALE instruction
  19544.  FSQRT instruction
  19545.  FST instruction
  19546.  FSTCW instruction
  19547.  FSTP instruction
  19548.  FSTSW instruction
  19549.  FSUB instruction
  19550.  FSUBP instruction
  19551.  FSUBR instruction
  19552.  FSUBRP instruction
  19553.  FTST instruction
  19554.  Full segment definitions
  19555.  Function return values
  19556.  FXAM instruction
  19557.  FXCH instruction
  19558.  FXTRACT instruction
  19559.  FYL2X instruction
  19560.  FYL2XP1 instruction
  19561.  
  19562.  G
  19563.  
  19564.  GE operator
  19565.  General-purpose registers
  19566.  Global directives
  19567.    defined
  19568.    illustrated
  19569.  Global flags
  19570.  Global scope
  19571.  Global symbols
  19572.  GROUP directive
  19573.  Group-relative segments
  19574.  Groups
  19575.    assembly listing
  19576.    defined
  19577.    illustrated
  19578.    size restriction
  19579.  GT operator
  19580.  
  19581.  H
  19582.  
  19583.  Hardware interrupts
  19584.  Help menu
  19585.  Help on DOS and BIOS functions
  19586.  Help topics
  19587.  Hexadecimal conversion example
  19588.  Hexadecimal radix
  19589.    in Debug expressions
  19590.    specifier
  19591.  HIGH operator
  19592.  High-level languages
  19593.    interfacing with
  19594.    memory model
  19595.  HLT instruction
  19596.  Huge memory model
  19597.  
  19598.  I
  19599.  
  19600.  /I option
  19601.  IDIV instruction
  19602.  IEEE format
  19603.  If blocks, run-time
  19604.  IF directives
  19605.  IF1 directive
  19606.  IF2 directive
  19607.  IFB directive
  19608.  IFDEF directive
  19609.  IFDIF directive
  19610.  IFE directive
  19611.  IFIDN directive
  19612.  IFNB directive
  19613.  IFNDEF directive
  19614.  Immediate operands
  19615.  Implied operands
  19616.  IMUL instruction
  19617.  IN instruction
  19618.  INC instruction
  19619.  INCLUDE directive
  19620.  INCLUDE environment variable
  19621.  Include files
  19622.    assembly listings
  19623.    using
  19624.    View menu command
  19625.  INCLUDELIB directive
  19626.  Incrementing
  19627.  Indeterminate operand
  19628.  Index checking
  19629.  Index, Help menu selection
  19630.  Index operator
  19631.  Index registers
  19632.  Indexed operands
  19633.  Indirect addressing modes (table)
  19634.  Indirection, pointer
  19635.  Initializing
  19636.    segment registers
  19637.    variables
  19638.  INS instruction
  19639.  INSTR directive
  19640.  Instruction-pointer register (IP)
  19641.  Instructions
  19642.    AAA
  19643.    AAD
  19644.    AAM
  19645.    AAS
  19646.    ADC
  19647.    ADD
  19648.    addition (list)
  19649.    AND
  19650.    bit test
  19651.    BOUND
  19652.    CALL
  19653.    CBW
  19654.    CLC
  19655.    CLD
  19656.    CLI
  19657.    CMP
  19658.    CMPS
  19659.    compare
  19660.    conditional-jump
  19661.    control-flow
  19662.    CWD
  19663.    DAA
  19664.    DAS
  19665.    data-manipulation
  19666.    DEC
  19667.    defined
  19668.    DIV
  19669.    ESC
  19670.    F2XM1
  19671.    FABS
  19672.    FADD
  19673.    FADDP
  19674.    FBLD
  19675.    FBSTP
  19676.    FCHS
  19677.    FCOM
  19678.    FCOMP
  19679.    FCOMPP
  19680.    FDIV
  19681.    FDIVP
  19682.    FDIVR
  19683.    FDIVRP
  19684.    FIADD
  19685.    FICOM
  19686.    FICOMP
  19687.    FIDIV
  19688.    FIDIVR
  19689.    FILD
  19690.    FIMUL
  19691.    FINIT
  19692.    FIST
  19693.    FISTP
  19694.    FISUB
  19695.    FISUBR
  19696.    FLD
  19697.    FLD1
  19698.    FLDCW
  19699.    FLDL2E
  19700.    FLDL2T
  19701.    FLDLG2
  19702.    FLDLN2
  19703.    FLDPI
  19704.    FLDZ
  19705.    FMUL
  19706.    FMULP
  19707.    FPATAN
  19708.    FPREM
  19709.    FPTAN
  19710.    FRNDINT
  19711.    FSCALE
  19712.    FSQRT
  19713.    FST
  19714.    FSTCW
  19715.    FSTP
  19716.    FSTSW
  19717.    FSUB
  19718.    FSUBP
  19719.    FSUBR
  19720.    FSUBRP
  19721.    FTST
  19722.    FXAM
  19723.    FXCH
  19724.    FXTRACT
  19725.    FYL2X
  19726.    FYL2XP1
  19727.    HLT
  19728.    IDIV
  19729.    IMUL
  19730.    IN
  19731.    INC
  19732.    INS
  19733.    INT
  19734.    INTO
  19735.    IRET
  19736.    JC
  19737.    Jcondition
  19738.    JCXZ
  19739.    JMP
  19740.    LAHF
  19741.    LDS
  19742.    LEA
  19743.    LEAVE
  19744.    LES
  19745.    LOCK
  19746.    LODS
  19747.    logical
  19748.    LOOP
  19749.    LOOPNE
  19750.    LOOPNZ
  19751.    MOV
  19752.    MOVS
  19753.    MUL
  19754.    multiplication (list)
  19755.    NEG
  19756.    NOP
  19757.    normal division (list)
  19758.    normal subtraction (list)
  19759.    NOT
  19760.    on-line help
  19761.    OR
  19762.    OUT
  19763.    OUTS
  19764.    POP
  19765.    POPA
  19766.    POPF
  19767.    program-flow
  19768.    PUSH
  19769.    PUSHA
  19770.    PUSHF
  19771.    REP
  19772.    REPE
  19773.    REPNE
  19774.    REPNZ
  19775.    REPZ
  19776.    RET
  19777.    RETF
  19778.    RETN
  19779.    reversed division (list)
  19780.    reversed subtraction (list)
  19781.    SAHF
  19782.    SBB
  19783.    SCAS
  19784.    STD
  19785.    STI
  19786.    STOS
  19787.    SUB
  19788.    TEST
  19789.    timing of
  19790.    WAIT
  19791.    XCHG
  19792.    XLAT
  19793.    XOR
  19794.  Instructions
  19795.  instructions
  19796.    AND
  19797.    LDS
  19798.    LES
  19799.    SHL
  19800.  Instruction-set directives
  19801.  INT instruction
  19802.  Integer formats (figure)
  19803.  Integers
  19804.  Interrupt-enable flag
  19805.  Interrupts
  19806.    defined
  19807.    operation of (figure)
  19808.    using
  19809.  INTO instruction
  19810.  IP register
  19811.  IRET instruction
  19812.  IRP directive
  19813.  IRPC directive
  19814.  
  19815.  J
  19816.  
  19817.  JC instruction
  19818.  Jcondition instruction
  19819.  JCXZ instruction
  19820.  JMP instruction
  19821.  JO instruction
  19822.  Jump tables
  19823.  Jumping conditionally
  19824.  
  19825.  K
  19826.  
  19827.  Keywords, on-line help for
  19828.  
  19829.  L
  19830.  
  19831.  /l option
  19832.  LABEL directive
  19833.  Labels
  19834.    macros, in
  19835.    near-code
  19836.    procedures
  19837.  LAHF instruction
  19838.  .LALL directive
  19839.  Language type
  19840.    COMM directive
  19841.    EXTRN directive
  19842.    .MODEL directive
  19843.    PROC statement
  19844.    PUBLIC directive
  19845.  Large memory model
  19846.  LDS instruction
  19847.  LE operator
  19848.  LEA instruction
  19849.  Learning assembly language
  19850.  LEAVE instruction
  19851.  LENGTH operator
  19852.  LES instruction
  19853.  .LFCOND directive
  19854.  Line-continuation character
  19855.  .LIST directive
  19856.  Listing
  19857.    controlling contents of
  19858.    false conditionals
  19859.    format
  19860.      addresses
  19861.      described
  19862.      EQU directive
  19863.      errors
  19864.      groups
  19865.      include files
  19866.      LOCK directive
  19867.      macro expansions
  19868.      macros
  19869.      Pass 1, reading
  19870.      records
  19871.      REP directive
  19872.      segment override
  19873.      segments
  19874.      structures
  19875.      symbols
  19876.    macros
  19877.    subtitles in
  19878.    suppressing output
  19879.    symbols and abbreviations in (table)
  19880.  Listing files
  19881.    creating
  19882.    editor-oriented
  19883.    example
  19884.    index to source code
  19885.    macro expansion
  19886.    Pass 1
  19887.    setting title
  19888.    suppressing tables
  19889.    View menu
  19890.    viewing
  19891.  Literal-character operator (!)
  19892.  Literal-text operator (\la)
  19893.  Loading
  19894.    constants to coprocessor
  19895.    coprocessor data
  19896.    far pointers
  19897.    values from strings
  19898.  LOCAL directive
  19899.    declaring stack variables
  19900.    symbols declared with
  19901.    using
  19902.  Local symbols
  19903.    defined
  19904.    in macros
  19905.  Local variables
  19906.    in procedures
  19907.    on stack (figure)
  19908.  Location counter ($)
  19909.  LOCK directive, assembly listing
  19910.  LOCK instruction
  19911.  LODS instruction
  19912.  Logarithms
  19913.  Logical bit operations (table of values)
  19914.  Logical instructions
  19915.  Logical operators
  19916.    vs. logical instructions
  19917.    (table)
  19918.  LOOP instruction
  19919.  Looping
  19920.    overview
  19921.    without use of CX
  19922.  LOOPNE instruction
  19923.  LOOPNZ instruction
  19924.  LOW operator
  19925.  LT operator
  19926.  
  19927.  M
  19928.  
  19929.  Machine code
  19930.  Macro comment operator (\sc\sc)
  19931.  MACRO directive
  19932.  Macro expansions, assembly listings
  19933.  Macros
  19934.    argument testing
  19935.    arguments
  19936.    assembly listing
  19937.    calling
  19938.    compared to procedures
  19939.    defined
  19940.    efficiency penalty
  19941.    exiting early
  19942.    expansions in listing
  19943.    local symbols
  19944.    nested
  19945.    operators
  19946.    parameters
  19947.    recursive
  19948.    redefining
  19949.    removing from memory
  19950.    string-manipulation directives (list)
  19951.    text
  19952.    viewing listing of
  19953.  Make dialog box (figure)
  19954.  MASK operator
  19955.  Masking bits
  19956.  Masking out a bit
  19957.  Masks, adjusting
  19958.  Math coprocessors
  19959.  Medium memory model
  19960.  Memory access, coordinating
  19961.  MEMORY combine type
  19962.  Memory models
  19963.    assembly procedure with
  19964.    default segments, types (table)
  19965.    described (list)
  19966.  Memory operands
  19967.    coprocessor
  19968.    defined
  19969.  Memory requirements
  19970.  Memory-model-independent procedures
  19971.  Messages
  19972.    to screen
  19973.    suppressing
  19974.  Microsoft Binary format
  19975.  Microsoft Binary Real format
  19976.  Microsoft segment model
  19977.  Mixed-language interface
  19978.    C
  19979.    entry sequences
  19980.    exit sequences
  19981.    local data
  19982.    register considerations
  19983.    return value
  19984.  Mixed-language programs
  19985.    building
  19986.    C and assembler
  19987.    program list (figure)
  19988.  .MODEL directive
  19989.  Model equate
  19990.  Modular programming
  19991.  Modulo division
  19992.  MOV instruction
  19993.  MOVS instruction
  19994.  .MSFLOAT directive
  19995.  MUL instruction
  19996.  Multiple modules
  19997.  Multiplying
  19998.    by 16
  19999.    by constants
  20000.    instructions
  20001.  Multiword values, shifting
  20002.  
  20003.  N
  20004.  
  20005.  NAME directive
  20006.  Names
  20007.    assigning
  20008.    external
  20009.    public
  20010.    reserved
  20011.  Naming convention
  20012.  NE operator
  20013.  Near pointers
  20014.  Near reference parameters, assembly
  20015.  NEAR type specifier
  20016.  nearStack
  20017.  nearStack keyword
  20018.  NEG instruction
  20019.  Negating
  20020.  Nesting
  20021.    conditional
  20022.    DUP operators
  20023.    include files
  20024.    macros
  20025.    procedures for Pascal
  20026.    segments
  20027.  Nonredefinable equates
  20028.  NOP instruction
  20029.  NOT instruction
  20030.  NOT operator
  20031.  No-wait coprocessor instructions
  20032.  Null class type
  20033.  Null string
  20034.  
  20035.  O
  20036.  
  20037.  Object records
  20038.  Octal radix
  20039.  OFFSET operator
  20040.    with group-relative segments
  20041.    with .MODEL directive
  20042.    overview
  20043.  ON GOSUB, emulating BASIC statement
  20044.  One-pass assembly option
  20045.  Operands
  20046.    based
  20047.    based indexed
  20048.    classical stack
  20049.    coprocessor
  20050.    defined
  20051.    destination
  20052.    direct memory
  20053.    immediate
  20054.    implied
  20055.    indeterminate
  20056.    indexed
  20057.    indirect memory
  20058.    location counter
  20059.    memory
  20060.    record field
  20061.    records
  20062.    register
  20063.    register indirect
  20064.    relocatable
  20065.    source
  20066.    strong typing
  20067.    structures
  20068.    types (list)
  20069.    undefined
  20070.  Operators
  20071.    AND
  20072.    arithmetic
  20073.    bitwise
  20074.    calculation
  20075.    defined
  20076.    DUP
  20077.    EQ
  20078.    expression (%)
  20079.    GE
  20080.    GT
  20081.    HIGH
  20082.    index
  20083.    LE
  20084.    LENGTH
  20085.    literal character (!)
  20086.    literal text
  20087.    logical (table)
  20088.    LOW
  20089.    LT
  20090.    macro comment (\sc\sc)
  20091.    macro (list)
  20092.    MASK
  20093.    NE
  20094.    NOT
  20095.    OFFSET
  20096.    OR
  20097.    precedence (table)
  20098.    PTR
  20099.    relational (table)
  20100.    SEG
  20101.    segment override (:). See
  20102.      (segment-override operator)
  20103.    shift
  20104.    SHL
  20105.    SHORT
  20106.    SHR
  20107.    SIZE
  20108.    structure-field name
  20109.    substitute (&)
  20110.    THIS
  20111.    TYPE
  20112.    .TYPE
  20113.    WIDTH
  20114.    XOR
  20115.  Options
  20116.    /a
  20117.    /AT
  20118.    /Cl
  20119.    /Cu
  20120.    /Cx
  20121.    /DOSSEG linker
  20122.    /Dsymbol
  20123.    /Ez
  20124.    /Fl
  20125.    /FPi
  20126.    /I
  20127.    /l
  20128.    /P1
  20129.    /s
  20130.    /Sa
  20131.    /Sd
  20132.    /Se
  20133.    setting inside environment
  20134.    /Sn
  20135.    /Sq
  20136.    summary
  20137.    /Sx
  20138.    /t
  20139.    /v
  20140.    /W
  20141.    /w
  20142.  Options menu
  20143.  OR instruction
  20144.  OR operator
  20145.  ORG directive
  20146.  %OUT directive
  20147.  OUT instruction
  20148.  Output messages to screen
  20149.  OUTS instruction
  20150.  Overflow flag
  20151.  Overflow interrupt
  20152.  
  20153.  P
  20154.  
  20155.  /P1 option
  20156.  Packed BCD numbers
  20157.  Packed decimal integers
  20158.  Packed decimal numbers
  20159.  PAGE align type
  20160.  Page breaks in assembly listings
  20161.  PAGE directive
  20162.  Page format, in listings
  20163.  PARA align type
  20164.  Parameter list, in PROC statement
  20165.  Parameters
  20166.    assembly, accessing from
  20167.    defining in procedures
  20168.    macros
  20169.    repeat blocks
  20170.    types, common (list)
  20171.  Parity flag
  20172.  Partial remainder
  20173.  Pascal
  20174.    case statements, emulating
  20175.    compiler
  20176.    for loops
  20177.    nestinglevel
  20178.    repeat loops, emulating
  20179.    return value (figure)
  20180.  Pass 1 listing
  20181.  Passing by
  20182.    near reference, assembly
  20183.    value
  20184.      assembly
  20185.      C
  20186.  % (percent sign), expression operator
  20187.  Percent sign (%), expression operator
  20188.  . (period)
  20189.  Period (.)
  20190.  Phase errors
  20191.  Pi, loading to coprocessor
  20192.  Plus sign (+), to separate registers
  20193.  Pointer indirection
  20194.  Pointer registers
  20195.  Pointers
  20196.    defining
  20197.    loading
  20198.  POP instruction
  20199.  POPA instruction
  20200.  POPF instruction
  20201.  Ports
  20202.    defined
  20203.    getting strings from
  20204.    sending strings to
  20205.  Precedence of operators
  20206.  Predefined equates
  20207.    CodeSize
  20208.    Cpu
  20209.    CurSeg
  20210.    DataSize
  20211.    FileName
  20212.    Model
  20213.    segment
  20214.    Version
  20215.    WordSize
  20216.  Preserving register values
  20217.  PROC directive
  20218.  PROC type specifier
  20219.  Procedure arguments, on stack (figure)
  20220.  Procedures
  20221.    compared to macros
  20222.    defining labels
  20223.    using
  20224.  Processor directives
  20225.  Product assistance report
  20226.  Program list (figure)
  20227.  Program-flow instructions
  20228.  PTR operator
  20229.    declaring parameters with
  20230.    declaring pointers with
  20231.    syntax
  20232.    used with data types
  20233.  PUBLIC combine type
  20234.  PUBLIC directive
  20235.  Public names
  20236.  Public symbols
  20237.  PURGE directive
  20238.  PUSH instruction
  20239.  PUSHA instruction
  20240.  PUSHF instruction
  20241.  
  20242.  Q
  20243.  
  20244.  QC environment
  20245.    building programs
  20246.    debugging commands
  20247.    described
  20248.    on-line help
  20249.    starting
  20250.  QC register variables
  20251.  QCL driver
  20252.    introduction
  20253.    options (list)
  20254.  ? (question mark)
  20255.  Question mark (?)
  20256.  Quick Advisor
  20257.  QuickAssembler
  20258.    assembly interfaces, writing
  20259.    environment
  20260.      See QC environment
  20261.  QuickBASIC compiler
  20262.  QuickC, interfacing with
  20263.  QWORD type specifier
  20264.  
  20265.  R
  20266.  
  20267.  .RADIX directive
  20268.  Radixes
  20269.    binary
  20270.    default
  20271.    specifiers (table)
  20272.  Real numbers
  20273.    arithmetic calculations
  20274.    designator (R)
  20275.    directives for defining (list)
  20276.    encoding
  20277.    format
  20278.    transfer instructions (list)
  20279.  RECORD directive
  20280.  Record operands
  20281.    compared to variables (figure)
  20282.    using
  20283.  Record type
  20284.    contents (figure)
  20285.    declaring
  20286.  Record variables
  20287.    compared to operands (figure)
  20288.    contents (figure)
  20289.    defining
  20290.  Records
  20291.    assembly listing
  20292.    declarations
  20293.    defining
  20294.    field operands
  20295.    fields
  20296.    initializing
  20297.    MASK operator
  20298.    object
  20299.    WIDTH operator
  20300.  Recursive macros
  20301.  Redefinable equates
  20302.  Redefining
  20303.    interrupts
  20304.    macros
  20305.  Register stacks
  20306.    classical-stack form (figure)
  20307.    data transfer (figure)
  20308.    memory form (figure)
  20309.    register form (figure)
  20310.    register-pop form (figure)
  20311.  Register variables, in C
  20312.  Registers
  20313.    accumulator
  20314.    AH
  20315.    AL
  20316.    altering within environment
  20317.    AX
  20318.    BH
  20319.    BL
  20320.    BP
  20321.    BX
  20322.    CH
  20323.    CL
  20324.    coprocessor
  20325.    CS
  20326.    CX
  20327.    defined
  20328.    DH
  20329.    DI
  20330.    DL
  20331.    DS
  20332.    DX
  20333.    ES
  20334.    flags
  20335.    general purpose
  20336.    index
  20337.    IP
  20338.    operands
  20339.    operands, coprocessor
  20340.    pointer
  20341.    preserving value of
  20342.    register-pop operands, coprocessor
  20343.    segment
  20344.    setting to zero
  20345.    SI
  20346.    SP
  20347.    SS
  20348.    strategy for using
  20349.    types of
  20350.    uses of
  20351.    watching contents of
  20352.  Registers window
  20353.  Relational operators (table)
  20354.  REP directive, assembly listing
  20355.  REP instruction
  20356.  REPE instruction
  20357.  Repeat blocks
  20358.    arguments
  20359.    defined
  20360.    parameters
  20361.    repeat for each argument
  20362.    repeat for each character of string
  20363.    repeat for specified count
  20364.  Repeating
  20365.    instructions, execution of
  20366.    using 8086-family string functions
  20367.  REPNE instruction
  20368.  REPNZ instruction
  20369.  Reporting problems
  20370.  REPT directive
  20371.  REPZ instruction
  20372.  Reserved names
  20373.  RET instruction
  20374.  RETF instruction
  20375.  RETN instruction
  20376.  Return value, offset (figure)
  20377.  Rotating bits (figure)
  20378.  
  20379.  S
  20380.  
  20381.  /s option
  20382.  /Sa option
  20383.  SAHF instruction
  20384.  .SALL directive
  20385.  SBB instruction
  20386.  Scaling by powers of two
  20387.  Scaling factor
  20388.  SCAS instruction
  20389.  Screen swapping
  20390.  \sc\sc (semicolons), operator
  20391.  /Sd option
  20392.  /Se option
  20393.  Search paths, include files
  20394.  Searching strings
  20395.  Sections in assembly listings
  20396.  SEG operator
  20397.  SEGMENT directive
  20398.  Segment register
  20399.  Segmented addressing
  20400.  Segment-order method
  20401.  (Segment-override operator)
  20402.    definition
  20403.    OFFSET operator, with
  20404.    string instructions, with
  20405.    XLAT instructions, with
  20406.  (segment-override operator)
  20407.    used with ES
  20408.  Segments
  20409.    absolute
  20410.    align type
  20411.    align type (figure)
  20412.    assembly listing
  20413.    combine type
  20414.      (figure)
  20415.      (list)
  20416.    defined
  20417.    extra
  20418.    group-relative offset
  20419.    groups
  20420.      defining
  20421.      structure (figure)
  20422.    MEMORY
  20423.    nesting
  20424.    ordering
  20425.    override, assembly listings
  20426.    override operator (:). See
  20427.      (segment-override operator)
  20428.    registers
  20429.    types
  20430.  Semicolons (\sc\sc), operator
  20431.  .SEQ directive
  20432.  Serious warnings
  20433.  Severe errors
  20434.  .SFCOND directive
  20435.  Shift operators
  20436.  Shifting
  20437.    bits
  20438.    multiword values
  20439.  SHL instruction
  20440.  SHL operator
  20441.  SHORT operator
  20442.  SHR operator
  20443.  SI register
  20444.  Sign flag
  20445.  Signed numbers
  20446.  Simplified segment defaults
  20447.  SIZE operator
  20448.  SIZESTR directive
  20449.  Small memory model
  20450.    defining attributes
  20451.    described
  20452.    setting up procedures
  20453.  Smart help
  20454.  /Sn option
  20455.  Source files, include
  20456.  Source modules
  20457.  Source operand
  20458.  Source string
  20459.  SP register
  20460.  Specifying calling convention
  20461.  /Sq option
  20462.  Square root
  20463.  SS register
  20464.  .STACK directive
  20465.  Stack
  20466.    allocating
  20467.    defined
  20468.    frame
  20469.    local variables on (figure)
  20470.    near and far types
  20471.    operands, coprocessor
  20472.    procedure arguments on (figure)
  20473.    registers
  20474.    segment
  20475.    status, after pushes and pops (figure)
  20476.    trace. See Calls command
  20477.    type
  20478.    use of
  20479.    variables
  20480.  STACK combine type
  20481.  Stand-alone programs
  20482.  .STARTUP directive
  20483.  Statement fields
  20484.  Statistics
  20485.  STD instruction
  20486.  Step Over command
  20487.  STI instruction
  20488.  STOS instruction
  20489.  String directives (list)
  20490.  Strings
  20491.    comparing
  20492.    constants
  20493.    declaring
  20494.    defined
  20495.    destination strings
  20496.    equates
  20497.    filling
  20498.    instructions, requirements for (table)
  20499.    loading values from
  20500.    moving
  20501.    null
  20502.    ports, transfer from and to
  20503.    searching
  20504.    source
  20505.    structures, in
  20506.    variables
  20507.  Strong typing
  20508.  STRUC directive
  20509.  Structure type
  20510.  Structure-field-name operator
  20511.  Structures
  20512.    assembly listing
  20513.    declarations
  20514.    definitions
  20515.    fields
  20516.    initializing
  20517.    operands
  20518.    overview
  20519.    variables
  20520.  SUB instruction
  20521.  Substitute operator (&)
  20522.  SUBSTR directive
  20523.  Substring directive
  20524.  Subtitles in listings
  20525.  Subtracting values
  20526.  SUBTTL directive
  20527.  /Sx option
  20528.  Symbols
  20529.    assembly listing
  20530.    communal
  20531.    defined
  20532.    defining from command line
  20533.    external
  20534.    global
  20535.    location counter
  20536.    public
  20537.    relocatable operands
  20538.    scope
  20539.  SYMDEB
  20540.  System requirements
  20541.  
  20542.  T
  20543.  
  20544.  /t option
  20545.  TBYTE type specifier
  20546.  Temporary real format (figure)
  20547.  TER
  20548.  Terminating execution
  20549.  TEST instruction
  20550.  Text macros
  20551.  .TFCOND directive
  20552.  THIS operator
  20553.  /TINY linker option
  20554.  Tiny memory model
  20555.  Tiny model option
  20556.  TITLE directive
  20557.  Trace Into command
  20558.  Tracing execution
  20559.  Transcendental calculations
  20560.  Transferring
  20561.    BCD integers
  20562.    binary integers
  20563.    real numbers
  20564.  Trap flag
  20565.  Trigonometric functions
  20566.  Tutorial books, assembly language
  20567.  Type
  20568.    ABS
  20569.    align
  20570.    class
  20571.    combine
  20572.    null class
  20573.    operand matching
  20574.    operators, described
  20575.    PROC
  20576.    record
  20577.    structure
  20578.  TYPE operator
  20579.  Type specifiers (list)
  20580.  .TYPE operator
  20581.  
  20582.  U
  20583.  
  20584.  Undefined operand
  20585.  Underscore (_)
  20586.  Unpacked BCD numbers
  20587.  Unsigned numbers
  20588.  Updates
  20589.  USES, in PROC statement
  20590.  
  20591.  V
  20592.  
  20593.  /v option
  20594.  Value parameters, C
  20595.  Variables
  20596.    automatic
  20597.    communal
  20598.    defined
  20599.    dynamic
  20600.    external
  20601.    floating point
  20602.    initializing
  20603.    integer
  20604.    local
  20605.    public
  20606.    real number
  20607.    record
  20608.    string
  20609.    structure
  20610.    watching value of
  20611.  Version equate
  20612.  View menu Include command
  20613.  
  20614.  W
  20615.  
  20616.  /W option
  20617.  /w option
  20618.  WAIT instruction
  20619.  Warning levels
  20620.  Watch Value command
  20621.  Watch Value dialog box (figure)
  20622.  Watchpoint command
  20623.  Weak typing in other assemblers
  20624.  While, emulating high-level-language statement
  20625.  WIDTH operator
  20626.  Width, structures
  20627.  WO memory operator
  20628.  WORD align type
  20629.  WORD PTR, in example
  20630.  WORD type specifier
  20631.  WordSize equate
  20632.  Write function, DOS
  20633.  
  20634.  X
  20635.  
  20636.  .XALL directive
  20637.  XCHG instruction
  20638.  XENIX compatibility
  20639.    pathnames, with / (forward slash)
  20640.    /sI
  20641.  XLAT instruction
  20642.  .XLIST directive
  20643.  XOR instruction
  20644.  XOR operator
  20645.  
  20646.  Z
  20647.  
  20648.  Zero flag
  20649.