home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 23 / IOPROG_23.ISO / SOFT / ASM / BCDASM.ZIP / BCDASM / DOC / BCD.TXT next >
Encoding:
Text File  |  1997-06-03  |  19.4 KB  |  546 lines

  1.  
  2.  
  3.   80x86 assembly language BCD math
  4.   --------------------------------
  5.  
  6.   Contents:    Copyright and disclaimer
  7.         General considerations
  8.         BCD formats, signs, min & max
  9.         BCD-related CPU instructions
  10.         Programming notes
  11.         - General notes
  12.         - Interfacing and user responsibilities
  13.         - Assembly formalities
  14.         - Procedural formalities
  15.         - Procedure interrelations
  16.         - Algorithms
  17.         - BCDASM equates and macros list
  18.         Credits
  19.         Related material
  20.  
  21.  
  22.  
  23.  
  24.   Copyright and disclaimer
  25.   ------------------------
  26.  
  27.   This text and the accompanying assembly source files and
  28.   binary files ("BCDASM") are copyright Morten Elling, 1997.
  29.  
  30.   You're free to use BCDASM for educational purposes and in
  31.   software (freeware, shareware, or commercial) but use it
  32.   at your own risk. BCDASM is offered without any guarantee.
  33.  
  34.   You're free to distribute the BCDASM file archive through
  35.   any media at your disposal on condition that the contents
  36.   of the file archive are not modified.
  37.  
  38.  
  39.   June, 1997
  40.  
  41.   Morten Elling
  42.   Ellemarksvej 12
  43.   DK-8000 Aarhus C
  44.   Denmark
  45.  
  46.   <mailto:elling@post1.tele.dk>
  47.  
  48.  
  49.  
  50.  
  51.   General considerations
  52.   ----------------------
  53.  
  54.   Numbers in business applications software must be large and
  55.   precise. Accounting books must balance so floating-point math
  56.   and its potential for rounding errors is insufficient.
  57.  
  58.   Performing business math in the CPU registers is OK if you
  59.   can make do with numbers in the range +21,474,836.47 to
  60.   -21,474,836.48 (32 bit). Inflation-ridden nations, large
  61.   companies, and Italian car dealers need bigger numbers.
  62.  
  63.   BCD math is basic in-memory integer math that lets you handle
  64.   numbers of considerable sizes, typically 18 digits but with
  65.   the capacity for several thousand digits. By tradition, BCDs
  66.   are used for business math and BCD schemes are supported by
  67.   several computers. All Intel's iAPx86 chips (PCs) execute BCD
  68.   instructions.
  69.  
  70.  
  71.   Numbers in BCD format are not as storage-efficient as numbers
  72.   in binary and they don't process quite as fast as their binary
  73.   cousins (additional CPU instructions are required to adjust
  74.   results). But being the sole base 10 format in an otherwise
  75.   completely hexadecimal and octal world, BCDs do offer some
  76.   advantages. Base 10 feels natural to humans (at least until
  77.   genetic engineering equips us with 16 fingers). BCDs are easy
  78.   to debug and convert to and from Ascii, and are easily divided
  79.   or multiplied by multiples of 10.
  80.  
  81.   BCDs are integers. Other than supplying a routine that will
  82.   display any number of decimals, BCDASM supports only integer
  83.   operations. This doesn't mean that you cannot use BCDs for
  84.   floating-point operations; it's unusual, though, and it will
  85.   require extra programming but it may pay off if your primary
  86.   concern is multi-digit results without rounding errors. With
  87.   BCDs, keeping track of the decimal point is easier than with
  88.   binary numbers.
  89.  
  90.  
  91.   If you are programming for a PC equipped with an FPU
  92.   (floating-point unit), consider using it. This requires the
  93.   use of 10-byte packed BCDs which is the only BCD format
  94.   recognized by the FPU. It also requires a conversion of the
  95.   BCD numbers to and from the FPU's temporary real format.
  96.   None of the BCDASM routines use FPU instructions since they
  97.   all use a caller-supplied BCD size.
  98.  
  99.  
  100.  
  101.  
  102.   BCD formats
  103.   -----------
  104.  
  105.   BCD stands for Binary Coded Decimal.
  106.  
  107.   BCD numbers are made up from the decimal numbers 0 thru 9
  108.   represented in binary:
  109.  
  110.                 Dec     Hex     Binary
  111.                 0       00h     0000
  112.                 1       01h     0001
  113.                 2       02h     0010
  114.                 3       03h     0011
  115.                 4       04h     0100
  116.                 5       05h     0101
  117.                 6       06h     0110
  118.                 7       07h     0111
  119.                 8       08h     1000
  120.                 9       09h     1001
  121.  
  122.   BCD numbers can be packed (the usual) storing two digits per
  123.   byte (the most-significant digit in the high-order 4 bits), or
  124.   un-packed storing one digit per byte (leaving the high-order 4
  125.   bits unused). The low-order 4 bits of a byte is also called
  126.   the low nibble, the high-order 4 bits the high nibble.
  127.  
  128.   Packed BCD is sometimes called 'packed decimal' or 'decimal
  129.   integer'. Unpacked BCD is sometimes called 'unpacked decimal'
  130.   or 'ASCII integer'.
  131.  
  132.         The decimal number 8 is represented as 08h in
  133.         packed BCD, and 08h in unpacked BCD. The decimal
  134.         number 28 is 28h in packed BCD (but 1Ch in binary)
  135.         and would require two unpacked BCD bytes.
  136.  
  137.  
  138.   Assemblers usually have limited support for BCD handling: the
  139.   DT directive which defines a ten-byte portion of storage, and
  140.   the TBYTE operator which can create a pointer to a ten-byte.
  141.   In Borland's Turbo Assembler (TASM), the DT directive defaults
  142.   to packed BCD format but may be used for other data types as
  143.   well; there is no assembler directive to support unpacked BCD.
  144.  
  145.   Examples (TASM.EXE v4.1):
  146.  
  147.   Pnum dt 81659247              ; Packed BCD (10 bytes)
  148.   Unum db 7,4,2,9,5,6,1,8,0,0
  149.        db 0,0,0,0,0,0,0,0,0,0   ; Unpacked BCD (20 bytes)
  150.   Dnum dt 81659247d             ; 'd' postfix for decimal number
  151.   Nnum dt -81659247             ; Negative packed BCD
  152.  
  153.   The numbers above are stored in memory as (hexadecimal):
  154.   Pnum 47  92  65  81  00  00  00  00  00  00
  155.   Unum 07  04  02  09  05  06  01  08  00  00
  156.        00  00  00  00  00  00  00  00  00  00
  157.   Dnum 6F  05  DE  04  00  00  00  00  00  00
  158.   Nnum 47  92  65  81  00  00  00  00  00  80 ; Top bit = 1
  159.  
  160.   i.e. the usual Intel little-endian format (the lower in
  161.   memory, the less significant).
  162.  
  163.         NOTE:
  164.         Borland's 32-bit assemblers (TASM32 v4.0, v5.0)
  165.         do not recognize the unary minus operator when
  166.         BCDs are initialized with the DT directive, i.e.
  167.         only non-negative BCD values can be initialized. 
  168.         Borland's 16-bit assemblers do, however, accept 
  169.         negative and zero BCD values with DT.
  170.  
  171.  
  172.   The term 'most significant byte' is avoided here and in the
  173.   source files, in the interest of clarity. Logically, which is
  174.   'most significant' in the variable Nnum above: the 9th byte,
  175.   the 8th, or the 3rd? It depends on what you're considering:
  176.   the BCD format, the numeric range, or the current variable.
  177.  
  178.   The sign bit (bit 79 of a tbyte) is 1 for negative numbers, 0
  179.   for positive or zero. The whole top _byte_ is used for the
  180.   sign, i.e. 00h or 80h (limiting the number range somewhat, but
  181.   making BCDs easier to program). To change a BCD from positive
  182.   to negative, only the top bit is changed. Note that the FPU
  183.   ignores anything but the sign bit in the top byte of a tbyte
  184.   (bits 72-78).
  185.  
  186.  
  187.   Assuming the top byte is used for the sign, we're left with
  188.   (10 - 1) * 2 = 18 digits for the number, hence the range of
  189.   a 10-byte packed signed BCD is:
  190.  
  191.         minimum -999,999,999,999,999,999
  192.         maximum +999,999,999,999,999,999
  193.  
  194.   or - since BCDs are primarily used for business calculations -
  195.  
  196.             +/-$9,999,999,999,999,999.99
  197.  
  198.   (almost 10 quadrillions in USA and France; 10,000 billions
  199.   elsewhere. Anyway, it was a lot of money in 1976).
  200.  
  201.  
  202.  
  203.         NOTE:
  204.         The 10-byte packed signed BCD described above is
  205.         the basic BCD type supported by the floating-
  206.         point unit (80x87), and it's the one generally
  207.         used in assembly source files.
  208.  
  209.         However, BCDs come in many flavors. Examples
  210.         include:
  211.         - 8-byte packed BCDs which fit better into the
  212.           80386's 32-bit registers
  213.         - A 6-byte packed BCD with 47 bits used for the
  214.           number and 1 bit for the sign (more storage-
  215.           efficient).
  216.         - A 12-byte unpacked BCD (easy Ascii-conversion)
  217.         - BCDs stored big-endian, even on Intel machines.
  218.           The numbers are easier to read this way when
  219.           debugging, but perhaps they originated from a
  220.           non-PC computer.
  221.  
  222.  
  223.  
  224.  
  225.  
  226.   BCD-related CPU and FPU instructions
  227.   (details in a separate file)
  228.   ------------------------------------
  229.  
  230.   The following members of the 8086 instruction set were
  231.   designed to support BCD math:
  232.  
  233.   - Packed BCD    (affects the AL and flags registers)
  234.           DAA     Decimal Adjust after Addition
  235.           DAS     Decimal Adjust after Subtraction
  236.   - Un-packed BCD (affects the AL, AH, and flags registers)
  237.           AAA     ASCII Adjust after Addition
  238.           AAS     ASCII Adjust after Subtraction
  239.           AAM     ASCII Adjust after Multiplication
  240.           AAD     ASCII Adjust before Division
  241.  
  242.  
  243.   Two FPU instructions support ten-byte BCD numbers:
  244.   - Packed BCD
  245.           FBLD    Load packed decimal
  246.           FBSTP   Store packed decimal and pop
  247.  
  248.  
  249.  
  250.  
  251.   Programming notes
  252.   -----------------
  253.  
  254.   --- General notes
  255.  
  256.   BCDASM supports C, (16-bit) Pascal, and assembly language.
  257.  
  258.   The source files include routines that perform basic math,
  259.   comparison, and conversion of packed, signed BCD numbers
  260.   (files bcd*.asm). A single module demonstrates operations on
  261.   unpacked, unsigned BCDs (file bcduu.asm).
  262.  
  263.   The application programming interface (API) of each procedure
  264.   (function) is described in detail in the procedure's source
  265.   file header. The headers have been extracted to the bcdapi.txt
  266.   file which serves as the BCDASM API reference. Similarly, the
  267.   algorithms used in BCDASM are described in comments embedded
  268.   in the source files.
  269.  
  270.   In this section, therefore, you'll find a description of some
  271.   general topics related to BCDASM, but not of the API.
  272.  
  273.  
  274.  
  275.  
  276.   --- Interfacing and user responsibilities
  277.  
  278.   All users must ensure that BCDASM routines run on an 80186
  279.   processor or compatible. No other initialization or shutdown
  280.   steps are required. BCDASM code does nothing but move bytes
  281.   and bits in memory; no operating system calls, interrupts,
  282.   port or file I/O.
  283.  
  284.  
  285.   Assembly language users should use a .MODEL statement with a
  286.   STDCALL, C, or PASCAL language specifier and include the
  287.   bcd.asi header file in modules that call BCDASM procedures.
  288.   (Note that a few procedures return carry, sign, or zero flags
  289.   but the comparison and shift routines return other flags than
  290.   you may expect from their names.)
  291.  
  292.   C language users must include the bcd.h header file in source
  293.   files referencing BCDASM functions.
  294.  
  295.   Both assembly language and C language users should link with
  296.   the appropriate BCDASM library file: bcd????.lib where ???? is
  297.   a memory model code. Run makelib.bat without parameters to see
  298.   a list of available memory models. Reassembly of the source
  299.   code for 16-bit models requires TASM v3.2 or later, whereas
  300.   the 32-bit flat model source code requires TASM v4.0 or later.
  301.  
  302.   Turbo Pascal users must reference the unit BCD (compiled as
  303.   bcd.tpu) in a USES statement to access BCDASM procedures and
  304.   functions (16-bit far code). Note that strings returned by
  305.   BCDASM are not Pascal-format but zero-terminated, C-style;
  306.   for convenience, the WriteZStr function is included in the
  307.   unit file.
  308.  
  309.  
  310.   BCDASM code typically adds 2-3 KB to the size of an executable
  311.   (max. 4 KB if all routines are linked), and the stack usage is 
  312.   max. 100 bytes (size of passed arguments and local variables).
  313.  
  314.  
  315.   All arguments passed to BCDASM routines must be correct; error
  316.   checking is minimal. In particular, pointers must be valid and
  317.   the byte size of BCD variables must be even and obey the
  318.   following limits.
  319.  
  320.   (In short: if you keep your BCD size even, and below 24 KB
  321.   - enough to hold 49,000+ digits - you're safe.)
  322.  
  323.     16-bit limits:
  324.     Min.      4  bytes
  325.     Max.      0FFFCh bytes (65,532 decimal)
  326.     Max.      07FFEh bytes (32,766 decimal) (*)
  327.  
  328.     32-bit limits:
  329.     Min.      4  bytes
  330.     Max.  0FFFFFFFCh bytes = approx. 4 GigaBytes
  331.     Max.  07FFFFFFEh bytes = approx. 2 GigaBytes (*)
  332.  
  333.     (*) Half-size operands required for sign extension,
  334.         multiplication, and division; bcdSx, bcdImul,
  335.         and bcdIdiv return results that are twice the
  336.         size of the source operand.
  337.  
  338.     Although BCDASM can handle the maximum sizes, your
  339.     operating system (or your patience) may not. Divide
  340.     the max. size figures by 3 or 4 to get the practical
  341.     limit imposed by the bcdFmt routine (BCD-to-Ascii).
  342.  
  343.  
  344.   If necessary, users must devise a method to initialize BCD
  345.   variables in software, typically by manipulating an array of
  346.   bytes. Assembly language users have the option of using the DT
  347.   directive when initializing variables.
  348.  
  349.   All BCDASM modules assume that bit 7 of the top byte of a BCD
  350.   number holds the sign and that bits 0-6 of the top byte are
  351.   undefined.
  352.  
  353.  
  354.  
  355.  
  356.   --- Assembly formalities
  357.  
  358.   The assembly source files were written for Borland's Turbo
  359.   Assembler v4.1 (MASM syntax). In order to keep symbol names
  360.   case-sensitive, TASM's /ml switch must be used, and include
  361.   files must be pointed to using the /i switch. No other
  362.   switches are needed since the source code has been arranged to
  363.   allow TASM's one-pass assembly. You can, however, pass the
  364.   desired memory model and processor to TASM, e.g.
  365.  
  366.     cd .\src
  367.     tasm /ml/i..\include\ /dMDL=16sp /dCPU=.8086 *.asm, ..\obj\;
  368.  
  369.   Refer to the model.inc file for these definitions; the default
  370.   model is <large, pascal> and the default processor is <.186>.
  371.   Except for bcd.asi, no include file contains an 'include'
  372.   statement.
  373.  
  374.  
  375.   Three features are used that require a recent version of TASM:
  376.   - prototyping (PROCDESC, extended CALL)     (TASM v3.2+)
  377.   - enhanced macro facilities (VARARG, REST)  (TASM v3.0+)
  378.   - model FLAT                                (TASM v4.0+)
  379.  
  380.   Unless you want the 32-bit flat model, it is fairly simple to
  381.   rewrite BCDASM for an earlier version of TASM (and slightly
  382.   less simple to rewrite it for Microsoft's assembler). After
  383.   two years with Ideal mode syntax, I'm back to MASM syntax but
  384.   kept the good habit of bracketing memory references.
  385.  
  386.   TASM's built-in high-level language support (PROC, USES, ARG,
  387.   LOCAL, RET, ENDP statements) is used extensively throughout
  388.   the source code. While it isn't necessary to use a .MODEL
  389.   statement to make use of the HLL or prototyping features, it
  390.   does make things somewhat easier:
  391.   - canned segments, available with .CODE, .DATA etc.
  392.   - language and code distance specifiers automatically
  393.     transferred to PROC, PROCDESC, PUBLIC, EXTRN etc.
  394.   - predefined CODEPTR and DATAPTR pointer types as well as
  395.     several model-related equates
  396.   - predefined .STARTUP and .EXIT macros available
  397.   - group override with OFFSET operator not needed
  398.  
  399.   Despite TASM's user guide, ARG, LOCAL, and DATAPTR don't work
  400.   with 32-bit code unless used with a .MODEL FLAT statement;
  401.   without it, args/locals are equated relative to BP, not EBP
  402.   (grrrrr...).
  403.  
  404.  
  405.  
  406.  
  407.   --- Procedural formalities
  408.  
  409.   Procedure entry and exit conditions are described in detail in
  410.   each procedure header (see bcdapi.txt). Most procedures return
  411.   information in the accumulator (AX/EAX) and -- for the benefit
  412.   of .asm users -- a few return flags.
  413.  
  414.   In the 16-bit memory models, no assumptions are made about the
  415.   ES register or direction flag on entry to a procedure. In the
  416.   models that use near data pointers (tiny, small, and medium),
  417.   DS is assumed to be = SS; in all other models, DS register
  418.   contents are unimportant to BCDASM routines (no variables in
  419.   DGROUP). Registers are preserved according to the requirements
  420.   of the selected model language (refer to the @uses macro in
  421.   modelt.inc). BCDASM supports C, STDCALL, and PASCAL. If the
  422.   direction flag is used, it is always cleared on exit.
  423.  
  424.   In the 32-bit flat model, Win32 rules apply: DS = ES = SS,
  425.   direction flag clear on entry and on exit. EAX, ECX, and EDX
  426.   registers may be modified, the rest are preserved. Calling
  427.   convention is STDCALL.
  428.  
  429.  
  430.   Assembly language users who want 16-bit 'flat' functionality
  431.   (near data models) can achieve this by equating @isDSeqESeqSS
  432.   to one (1); it'll save ES loads and ES overrides. Equating
  433.   @isDirectionUp to one (1) saves redundant CLD instructions.
  434.   See modelt.inc for these equates.
  435.  
  436.  
  437.  
  438.  
  439.   --- Procedure interrelations
  440.  
  441.   No 'internal' calls; each module is self-contained.
  442.  
  443.  
  444.  
  445.  
  446.   --- Algorithms
  447.  
  448.   Basic multi-digit number-processing all the way, using LODS,
  449.   STOS, and LOOP instructions. BCD multiplication is slow
  450.   because this operation involves heavy use of MUL and AAM
  451.   instructions which are among the very slowest on an 8086 but
  452.   part of the BCD scheme. BCD division is similarly slow due to
  453.   a divide-by-repeated-subtraction approach.
  454.  
  455.   I've emphasized modularity and clarity over speed during the
  456.   development since multi-digit in-memory calculations are used
  457.   primarily for their capacity.
  458.  
  459.   For much the same reasons, I've used equates (rax, rbx etc.)
  460.   for the actual register names (uppercase AX, BX etc. is used
  461.   for explicit 16-bit operations; lowercase eax, ebx etc. for
  462.   32-bit). Attempting to write assembly for both 16-bit and
  463.   32-bit like this is definitely _not_ to be recommended but I
  464.   wanted to try it out for this occasion. True 80386+ support
  465.   is rudimentary.
  466.  
  467.   BCDASM leaves room for improvement; grep for "ToDo" to locate
  468.   a few places.
  469.  
  470.  
  471.  
  472.  
  473.   --- BCDASM equates and macros list
  474.  
  475.   Defined by TASM:        Defined or redefined by:
  476.   - @Model, @Interface,
  477.     @CodeSize, @DataSize,
  478.     DATAPTR            .model directive
  479.   - @data, @stack        .model directive,
  480.                   segment opening
  481.   - @WordSize            segment opening,
  482.                   processor directive
  483.   - @Startup            built-in .startup macro
  484.  
  485.  
  486.   (The equates and macros defined in model.inc and
  487.   modelt.inc are not redefined by any BCDASM module)
  488.  
  489.   Equates defined in model.inc:
  490.   - CPU, MDL, @fartext
  491.  
  492.   Equates defined in modelt.inc:
  493.   - @isCodeNear, @isDataFar, @isDataNear, @isStackFar,
  494.     @isStackNear, @isUse32, @isWin32, @is386
  495.   - @isDirectionUp, @isDSeqESeqSS
  496.   - @ES, @dui, @uint, @dsaddr, @dsr, @ssr, @nullptr
  497.   - @bptr, @uiptr, @wptr, sh
  498.   - @fram
  499.  
  500.   Macros defined in modelt.inc:
  501.   - @CODESEG, @alignn, @ptype, @proto, @uses
  502.   - @LDSEGM, @LDS, @LES, @cld, @shl, @shr
  503.   - @enter, @leave, ENTERW,ENTERD,LEAVEW,LEAVED
  504.  
  505.  
  506.  
  507.  
  508.  
  509.   Credits
  510.   -------
  511.  
  512.   BCDASM is my own work but it may not have reached the .LIB
  513.   state without a glance or two in "intel.zip" from 1990, a
  514.   collection of assembly source files which unfortunately has
  515.   no named author and no copyright notice. Specifically, the
  516.   division and comparison routines in BCDASM were inspired by
  517.   bcddiv.asm and bcdcmp.asm in "intel.zip" but completely
  518.   rewritten for this occasion.
  519.  
  520.   The algorithm used in the multiplication routine was taken
  521.   from Ray Duncan's MPMUL1.ASM which appeared in PC Magazine
  522.   Nov 28, 1989 (vol. 8 no. 20).
  523.  
  524.  
  525.  
  526.  
  527.   Related material
  528.   ----------------
  529.  
  530.   HugeCalc by Neil J. Rubenking, includes Turbo Pascal v6.0
  531.   source code. HugeCalc performs +-*/ exponential and factorial
  532.   math on up to 254-digit integers, using pascal's string type
  533.   to store the numbers as digits. Implemented as a command-line
  534.   calculator, it supports unsigned numbers only. Downloadable at
  535.   <http://www.pcmag.com> as part of VOL10N16.ZIP, the Sept 24,
  536.   1991 PC Magazine file archive.
  537.  
  538.  
  539.   MONEY, a C++ money class by Adolfo di Mare, includes Borland
  540.   C++ v2.0 source code. Uses C's double type (floor(double *
  541.   100.0)) with no fractional part to store the numbers, allowing
  542.   15+ digit precision. Downloadable at Simtel as
  543.   <ftp://ftp.simtel.net/pub/simtelnet/msdos/cpluspls/money.zip>.
  544.  
  545.  
  546.