home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / odtlktv4.zip / ODTLKT / TOOLKIT / INC / BASEMACA.INC < prev    next >
Text File  |  1995-11-22  |  89KB  |  3,598 lines

  1. ;    SCCSID = @(#)basemaca.inc    6.9 91/09/20
  2. ;***    BASEMACA.INC
  3. ;
  4. ;    SCCSID = @(#)basemaca.inc    6.9 91/09/20
  5. ;
  6. ;    Macros required for other include files
  7. ;    Copyright (c) 1988, 1993 IBM Corporation
  8. ;    Copyright (c) 1988 Microsoft Corporation
  9. ;
  10. ;    DESCRIPTION
  11. ;
  12. ;    This file provides the following macros (enabled with INCL_DEF):
  13. ;
  14. ;      DefEntry    prototype-name
  15. ;      DefType    type-name,{type,structure}[,def-value[,def-rept]]
  16. ;      DefStruc    [type-name[,{type,structure}]]
  17. ;      EndStruc    type-name[,{type,structure}]
  18. ;      DefSeg    seg,class,type,align,combine,use,link-class
  19. ;      DefCode    [{EXPORT,IMPORT,PRIVATE,LOCAL}[,class[,{C,PASCAL}]]]
  20. ;      EndCode
  21. ;      DefData    [{EXPORT,IMPORT,PRIVATE,LOCAL}[,class[,{C,PASCAL}]]]
  22. ;      EndData
  23. ;      DefCon    constant-name,value
  24. ;      DefFn     function-name
  25. ;
  26. ;    Always enabled:
  27. ;
  28. ;      B1EMac    [rep] {ins ...,movs ...,stos ...}
  29. ;      Break     subtitle
  30. ;      Procedure    name[,distance[,scope[,treg[,abase[,cseg[,blank]]]]]]
  31. ;      EndProc    name[,NOCHECK]
  32. ;      ProcError    message
  33. ;      GenPublic    name[,local]
  34. ;      GenHybrid    name[,[local] [,usecall]]
  35. ;      GenFar32    name[,[local] [,usecall]]
  36. ;      Entry     name[,distance[,scope]]
  37. ;      ArgVar    name,{type,length}[,lowname[,highname[,nowarn]]]
  38. ;      LocalVar    name,{type,length}[,lowname[,highname[,pad]]]
  39. ;      EnterProc    [varlist]
  40. ;      LeaveProc
  41. ;      ExitProc
  42. ;      FallInto    procedure-name
  43. ;      FallFrom    procedure-name
  44. ;      SaveReg    [reglist]
  45. ;      RestoreReg    [reglist]
  46. ;      CPUMode    {cpu,RESET}
  47. ;      CallFn    name[,arglist]
  48. ;      PCall     name[,arglist]
  49. ;      CCall     name[,arglist][,modifiers]
  50. ;      BugBug    date,initials,note
  51. ;      movzxESP                        ;whs
  52. ;      SSToDS_PS    dest-reg[,source]            ;whs
  53. ;      DSToSS_PS    dest-reg[,source]            ;whs
  54. ;      SSToDS    dest-reg[,source]
  55. ;      DSToSS    dest-reg[,source]
  56. ;      PopAll
  57. ;      PushAll
  58. ;
  59. ;      IODELAY
  60. ;      RETC        [n]
  61. ;      RETP        [n]
  62. ;      RETD        [n]
  63. ;      RETND     [n]
  64. ;      RETFD     [n]
  65. ;      RETW        [n]
  66. ;      RETNW     [n]
  67. ;      RETFW     [n]
  68. ;      PUSHD     value
  69. ;      POPD        value
  70. ;      LOADSL    reg,sel
  71. ;      LOADAR    reg,sel
  72. ;      VERIFYREAD    sel,scratch-reg
  73. ;      VERIFYWRITE    sel,scratch-reg
  74. ;
  75. ;      FLATOffset            ;text-macros
  76. ;
  77. ;    MAGIC DEFINES
  78. ;
  79. ;      NOALIGN     Disables automatic data alignment
  80. ;      NOBUGBUG    Disables BUGBUG messages
  81. ;      ERRBUGBUG   Forces compilation error if any BUGBUGs exist
  82. ;
  83. ;    MODIFICATION HISTORY
  84. ;    10/03/88    JTP     Created.
  85. ;    11/29/88    JTP     Added new macros (DefCode, DefData, etc)
  86. ;    12/15/88    JTP     Added auto-alignment-and-warning for data
  87. ;                according to segment type (can be disabled if
  88. ;                NOALIGN defined)
  89. ;    07/17/90    JTP     Added andb, orb, testb, btrx and bsrx macros
  90. ;
  91.  
  92. NULL    equ    0
  93. FALSE    equ    0
  94. TRUE    equ    -1
  95.  
  96. ?C    equ 1        ; constants for ?model
  97. ?PASCAL equ 2
  98.  
  99. ?PUBLIC equ 1        ; constants for ?declare
  100. ?EXTRN    equ 2
  101.  
  102. ?CS_16bit equ 0     ; constants for ?cstype
  103. ?CS_32bit equ 1
  104. ?cstype  = ?CS_16bit
  105. ?wdsz     = 2
  106. ?cpumode = 286
  107.  
  108. ?nsegs     = 0        ; counter for segment nesting
  109. ?nstrucs = 0        ; counter for structure nesting
  110. ?nfields = 0        ; tracks field # within a structure
  111.  
  112. ?segname equ <>     ; initialize variables for DefCode/DefData....
  113. ?curseg  equ <>
  114. ?model     = NULL
  115. ?declare = NULL
  116.  
  117. ?case     = TRUE     ; assume case-sensitivity
  118. ifdef ?CASE
  119.   ?case  = FALSE    ; apparently, a bad assumption...
  120. endif
  121.  
  122. ;*** Text-macros
  123.  
  124. FLAToffset equ <offset FLAT:>
  125.  
  126. ifdef INCL_DEF
  127.  
  128. ;*** DefEntry - Declare a new function prototype-type
  129. ;
  130. ;   ENTRY
  131. ;    dtyp        prototype-type name
  132. ;
  133.  
  134. DefEntry macro dtyp
  135.       dtyp macro pname,args
  136.          ifndef pname
  137.            ?&&pname = 0
  138.            irp x,<args>
  139.          ifdef INCL_TYPES
  140.            ifidn <x>,<...>
  141.              ?&&pname = -1
  142.              exitm
  143.            elseifidni <x>,<void>
  144.              ?&&pname = 0
  145.              exitm
  146.            elseifndef x
  147.             if1
  148.              %out Unknown type (&x) in function:  &pname
  149.             endif
  150.            endif
  151.          endif
  152.          ?&&pname = ?&&pname + 1
  153.            endm
  154.          endif
  155.        endm
  156.      endm
  157.  
  158. ;*** DefType - Define a type
  159. ;
  160. ;   Used to define new type-macros.
  161. ;
  162. ;   ENTRY
  163. ;    type    the type (a type-macro name)
  164. ;    dtyp    the type declarator (eg, db, dw, structure name, etc)
  165. ;    defval    a default initial value; 0 if unspecified
  166. ;    defrep    a default repeat count; 1 if unspecified (ie, # elements)
  167. ;
  168. ;   EXAMPLES
  169. ;    DefType HVDM,dd
  170. ;
  171. ;      becomes:
  172. ;
  173. ;    HVDM macro var,val,rep
  174. ;         ?DefVar <dd>,var,<val>,<>,<rep>,<>
  175. ;         endm
  176. ;
  177. ;    DefType NAME,db,byte,' ',8
  178. ;
  179. ;      becomes
  180. ;
  181. ;    NAME macro var,val,rep
  182. ;         ?DefVar <db>,var,<val>,<' '>,<rep>,<8>
  183. ;         endm
  184. ;
  185.  
  186. DefType macro type,dtyp,defval,defrep
  187.       ifdef ?&dtyp
  188.         @&type catstr @&dtyp
  189.         ?&type = ?&dtyp
  190.   type        macro   var,val,rep
  191.          % ?DefVar    <@&dtyp>,var,<val>,<defval>,<rep>,<defrep>
  192.         endm
  193.       else
  194.         @&type equ <dtyp>
  195.         ifidni <dtyp>,<db>
  196.           ?&type = 1
  197.         elseifidni <dtyp>,<dw>
  198.           ?&type = 2
  199.         elseifidni <dtyp>,<dd>
  200.           ?&type = 4
  201.         elseifidni <dtyp>,<df>
  202.           ?&type = 6
  203.         elseifidni <dtyp>,<dq>
  204.           ?&type = 8
  205.         elseifidni <dtyp>,<dt>
  206.           ?&type = 10
  207.         elseifnb <dtyp>
  208.           ?&type = size dtyp
  209.         endif
  210.   type        macro   var,val,rep
  211.           ?DefVar  <dtyp>,var,<val>,<defval>,<rep>,<defrep>
  212.         endm
  213.       endif
  214.     endm
  215.  
  216. ;*** DefStruc - Define a structure-type
  217. ;
  218. ;   Used to define new structure-type-macros.
  219. ;
  220. ;   ENTRY
  221. ;    type    the type (a type-macro name;  optional)
  222. ;    dtyp    the type declarator (eg, crf_s, ptda_s, etc;  optional)
  223. ;
  224. ;   EXAMPLES
  225. ;    DefStruc
  226. ;      ULONG crf_EDI
  227. ;      ULONG crf_ESI
  228. ;    EndStruc CRF,crf_s
  229. ;
  230. ;      becomes:
  231. ;
  232. ;    crf_s struc
  233. ;     crf_EDI dd 0
  234. ;     crf_ESI dd 0
  235. ;    crf_s ends
  236. ;    CRF  macro var,val,rep
  237. ;         ?DefVar <crf_s>,var,<val>,<>,<rep>,<>
  238. ;         endm
  239. ;
  240.  
  241. DefStruc macro type,dtyp
  242.        if ?nstrucs
  243.          if1
  244.            %out Nested structure definitions not supported
  245.            .err
  246.          endif
  247.        else
  248.          ?nstrucs = ?nstrucs + 1
  249.          ?nfields = 0
  250.          ?OPENSTRUC macro
  251.          dtyp struc
  252.          endm
  253.          ?CLOSESTRUC macro
  254.          dtyp ends
  255.          endm
  256.          ?TYPE macro mtyp
  257.            DefType mtyp,dtyp
  258.          endm
  259.        endif
  260.      endm
  261.  
  262. ;*** EndStruc - End a structure-type definition (see DefStruc)
  263. ;
  264. ;   ENTRY
  265. ;    type    the type (a type-macro name)
  266. ;    dtyp    the type declarator (eg, crf_s, ptda_s, etc;
  267. ;        optional if specified in the DefStruc directive)
  268. ;
  269.  
  270. EndStruc macro    type,dtyp
  271.        ifnb <dtyp>
  272.          ?OPENSTRUC macro
  273.          dtyp struc
  274.          endm
  275.          ?CLOSESTRUC macro
  276.          dtyp ends
  277.          endm
  278.        endif
  279.        ?OPENSTRUC
  280.        if ?nfields GE 1
  281.        ?F1
  282.        endif
  283.        if ?nfields GE 2
  284.        ?F2
  285.        endif
  286.        if ?nfields GE 3
  287.        ?F3
  288.        endif
  289.        if ?nfields GE 4
  290.        ?F4
  291.        endif
  292.        if ?nfields GE 5
  293.        ?F5
  294.        endif
  295.        if ?nfields GE 6
  296.        ?F6
  297.        endif
  298.        if ?nfields GE 7
  299.        ?F7
  300.        endif
  301.        if ?nfields GE 8
  302.        ?F8
  303.        endif
  304.        if ?nfields GE 9
  305.        ?F9
  306.        endif
  307.        if ?nfields GE 10
  308.        ?F10
  309.        endif
  310.        if ?nfields GE 11
  311.        ?F11
  312.        endif
  313.        if ?nfields GE 12
  314.        ?F12
  315.        endif
  316.        if ?nfields GE 13
  317.        ?F13
  318.        endif
  319.        if ?nfields GE 14
  320.        ?F14
  321.        endif
  322.        if ?nfields GE 15
  323.        ?F15
  324.        endif
  325.        if ?nfields GE 16
  326.        ?F16
  327.        endif
  328.        if ?nfields GE 17
  329.        ?F17
  330.        endif
  331.        if ?nfields GE 18
  332.        ?F18
  333.        endif
  334.        if ?nfields GE 19
  335.        ?F19
  336.        endif
  337.        if ?nfields GE 20
  338.        ?F20
  339.        endif
  340.        if ?nfields GE 21
  341.        ?F21
  342.        endif
  343.        if ?nfields GE 22
  344.        ?F22
  345.        endif
  346.        if ?nfields GE 23
  347.        ?F23
  348.        endif
  349.        if ?nfields GE 24
  350.        ?F24
  351.        endif
  352.        if ?nfields GE 25
  353.        ?F25
  354.        endif
  355.        if ?nfields GE 26
  356.        ?F26
  357.        endif
  358.        if ?nfields GE 27
  359.        ?F27
  360.        endif
  361.        if ?nfields GE 28
  362.        ?F28
  363.        endif
  364.        if ?nfields GE 29
  365.        ?F29
  366.        endif
  367.        if ?nfields GE 30
  368.        ?F30
  369.        endif
  370.        if ?nfields GE 31
  371.        ?F31
  372.        endif
  373.        if ?nfields GE 32
  374.        ?F32
  375.        endif
  376.        if ?nfields GE 33
  377.        ?F33
  378.        endif
  379.        if ?nfields GE 34
  380.        ?F34
  381.        endif
  382.        if ?nfields GE 35
  383.        ?F35
  384.        endif
  385.        if ?nfields GE 36
  386.        ?F36
  387.        endif
  388.        if ?nfields GE 37
  389.        ?F37
  390.        endif
  391.        if ?nfields GE 38
  392.        ?F38
  393.        endif
  394.        if ?nfields GE 39
  395.        ?F39
  396.        endif
  397.        if ?nfields GE 40
  398.        ?F40
  399.        endif
  400.        if ?nfields GE 41
  401.        ?F41
  402.        endif
  403.        if ?nfields GE 42
  404.        ?F42
  405.        endif
  406.        if ?nfields GE 43
  407.        ?F43
  408.        endif
  409.        if ?nfields GE 44
  410.        ?F44
  411.        endif
  412.        if ?nfields GE 45
  413.        ?F45
  414.        endif
  415.        if ?nfields GE 46
  416.        ?F46
  417.        endif
  418.        if ?nfields GE 47
  419.        ?F47
  420.        endif
  421.        if ?nfields GE 48
  422.        ?F48
  423.        endif
  424.        if ?nfields GE 49
  425.        ?F49
  426.        endif
  427.        if ?nfields GE 50
  428.        ?F50
  429.        endif
  430.        if ?nfields GE 51
  431.        ?F51
  432.        endif
  433.        if ?nfields GE 52
  434.        ?F52
  435.        endif
  436.        if ?nfields GE 53
  437.        ?F53
  438.        endif
  439.        if ?nfields GE 54
  440.        ?F54
  441.        endif
  442.        if ?nfields GE 55
  443.        ?F55
  444.        endif
  445.        if ?nfields GE 56
  446.        ?F56
  447.        endif
  448.        if ?nfields GE 57
  449.        ?F57
  450.        endif
  451.        if ?nfields GE 58
  452.        ?F58
  453.        endif
  454.        if ?nfields GE 59
  455.        ?F59
  456.        endif
  457.        if ?nfields GE 60
  458.        ?F60
  459.        endif
  460.        if ?nfields GE 61
  461.        ?F61
  462.        endif
  463.        if ?nfields GE 62
  464.        ?F62
  465.        endif
  466.        if ?nfields GE 63
  467.        ?F63
  468.        endif
  469.        if ?nfields GE 64
  470.        ?F64
  471.        endif
  472.        if ?nfields GE 65
  473.        ?F65
  474.        endif
  475.        if ?nfields GE 66
  476.        ?F66
  477.        endif
  478.        if ?nfields GE 67
  479.        ?F67
  480.        endif
  481.        if ?nfields GE 68
  482.        ?F68
  483.        endif
  484.        if ?nfields GE 69
  485.        ?F69
  486.        endif
  487.        if ?nfields GE 70
  488.        ?F70
  489.        endif
  490.        if ?nfields GE 71
  491.        ?F71
  492.        endif
  493.        if ?nfields GE 72
  494.        ?F72
  495.        endif
  496.        if ?nfields GE 73
  497.        ?F73
  498.        endif
  499.        if ?nfields GE 74
  500.        ?F74
  501.        endif
  502.        if ?nfields GE 75
  503.        ?F75
  504.        endif
  505.        if ?nfields GE 76
  506.        ?F76
  507.        endif
  508.        if ?nfields GE 77
  509.        ?F77
  510.        endif
  511.        if ?nfields GE 78
  512.        ?F78
  513.        endif
  514.        if ?nfields GE 79
  515.        ?F79
  516.        endif
  517.        if ?nfields GE 80
  518.        ?F80
  519.        endif
  520.        if ?nfields GE 81
  521.        ?F81
  522.        endif
  523.        if ?nfields GE 82
  524.        ?F82
  525.        endif
  526.        if ?nfields GE 83
  527.        ?F83
  528.        endif
  529.        if ?nfields GE 84
  530.        ?F84
  531.        endif
  532.        if ?nfields GE 85
  533.        ?F85
  534.        endif
  535.        if ?nfields GE 86
  536.        ?F86
  537.        endif
  538.        if ?nfields GE 87
  539.        ?F87
  540.        endif
  541.        if ?nfields GE 88
  542.        ?F88
  543.        endif
  544.        if ?nfields GE 89
  545.        ?F89
  546.        endif
  547.        if ?nfields GE 90
  548.        ?F90
  549.        endif
  550.        if ?nfields GE 91
  551.        ?F91
  552.        endif
  553.        if ?nfields GE 92
  554.        ?F92
  555.        endif
  556.        if ?nfields GE 93
  557.        ?F93
  558.        endif
  559.        if ?nfields GE 94
  560.        ?F94
  561.        endif
  562.        if ?nfields GE 95
  563.        ?F95
  564.        endif
  565.        if ?nfields GE 96
  566.        ?F96
  567.        endif
  568.        if ?nfields GE 97
  569.        ?F97
  570.        endif
  571.        if ?nfields GE 98
  572.        ?F98
  573.        endif
  574.        if ?nfields GE 99
  575.        ?F99
  576.        endif
  577.        if ?nfields GE 100
  578.        ?F100
  579.        endif
  580.        if ?nfields GE 101
  581.        ?F101
  582.        endif
  583.        if ?nfields GE 102
  584.        ?F102
  585.        endif
  586.        if ?nfields GE 103
  587.        ?F103
  588.        endif
  589.        if ?nfields GE 104
  590.        ?F104
  591.        endif
  592.        if ?nfields GE 105
  593.        ?F105
  594.        endif
  595.        if ?nfields GE 106
  596.        ?F106
  597.        endif
  598.        if ?nfields GE 107
  599.        ?F107
  600.        endif
  601.        if ?nfields GE 108
  602.        ?F108
  603.        endif
  604.        if ?nfields GE 109
  605.        ?F109
  606.        endif
  607.        if ?nfields GE 110
  608.        ?F110
  609.        endif
  610.        if ?nfields GE 111
  611.        ?F111
  612.        endif
  613.        if ?nfields GE 112
  614.        ?F112
  615.        endif
  616.        if ?nfields GE 113
  617.        ?F113
  618.        endif
  619.        if ?nfields GE 114
  620.        ?F114
  621.        endif
  622.        if ?nfields GE 115
  623.        ?F115
  624.        endif
  625.        if ?nfields GE 116
  626.        ?F116
  627.        endif
  628.        if ?nfields GE 117
  629.        ?F117
  630.        endif
  631.        if ?nfields GE 118
  632.        ?F118
  633.        endif
  634.        if ?nfields GE 119
  635.        ?F119
  636.        endif
  637.        if ?nfields GE 120
  638.        ?F120
  639.        endif
  640.        if1
  641.          if ?nfields GT 120
  642.            %out More than 120 fields in structure-type:  &type
  643.            .err
  644.          endif
  645.        endif
  646.        ?CLOSESTRUC
  647.        ifb <dtyp>
  648.          ?TYPE type
  649.        else
  650.          DefType type,dtyp
  651.        endif
  652.        ?nstrucs = ?nstrucs - 1
  653.        rept ?nfields
  654.          ?Purge <?F>,%?nfields
  655.          ifdef DEBUG
  656.            if DEBUG eq 1
  657.          ?InvPrg <?D>,%?nfields
  658.            endif
  659.          endif
  660.          ?nfields = ?nfields - 1
  661.        endm
  662.      endm
  663.  
  664. ;*** DefSeg - Define a segment
  665. ;
  666. ;   ENTRY
  667. ;
  668. ;   EFFECTS
  669. ;
  670.  
  671. DefSeg macro sname,class,stype,align,combine,use,lclass
  672.      ifdif <stype>,<CODE>
  673.        ifdif <stype>,<DATA>
  674.          if1
  675.            %out Unknown type (stype) for segment:  sname
  676.          endif
  677.        endif
  678.      endif
  679.      @&class&_&stype equ <sname>   ;; save away the real segment name
  680.      ?&class&_&stype equ <use>     ;; save away use (ie, USE16, etc)
  681.      sname SEGMENT align combine use lclass
  682.      sname ENDS
  683.        endm
  684.  
  685. ;*** DefCode - Begin code definitions
  686. ;
  687. ;   ENTRY
  688. ;    scope    PRIVATE (default), EXPORT or IMPORT
  689. ;
  690. ;    class    GLOBAL, INIT, etc.  (default is none)
  691. ;
  692. ;    model    C or PASCAL or none;  if C, function names are prepended
  693. ;        with an underscore;  if PASCAL, names are upper-cased
  694. ;
  695. ;    type    USE16 or USE32 or none
  696. ;
  697. ;   EFFECTS
  698. ;    Sets ?nsegs, ?segname, ?cstype, ?model and ?declare
  699. ;
  700.  
  701. DefCode macro scope,class,model,type
  702.       ?PushSeg %?nsegs
  703.       ifdef @&class&_CODE
  704.         ?segname catstr @&class&_CODE
  705.         ?SetType %?&class&_CODE
  706.       elseifnb <class>
  707.         ?segname equ <class>
  708.         ?SetType type
  709.       endif
  710.       ?OpenSeg scope,class,model,type
  711.      endm
  712.  
  713. ;*** EndCode - End code definitions
  714. ;
  715. ;   ENTRY
  716. ;    Same as above (although everything is optional)
  717. ;
  718.  
  719. EndCode macro scope,class,model,type
  720.       ?CloseSeg scope,class,model,type,DefCode
  721.       ?PopSeg %?nsegs
  722.      endm
  723.  
  724. ;*** DefData - Begin data definitions
  725. ;
  726. ;   ENTRY
  727. ;    scope    PRIVATE (default), EXPORT or IMPORT
  728. ;
  729. ;    class    GLOBAL, INIT, INSTANCE, etc.  (default is none)
  730. ;
  731. ;    model    C or PASCAL or none;  if C, function names are prepended
  732. ;        with an underscore;  if PASCAL, names are upper-cased
  733. ;   EFFECTS
  734. ;    Sets ?nsegs, ?segname, ?cstype, ?model and ?declare
  735. ;
  736.  
  737. DefData macro scope,class,model,type
  738.       ?PushSeg %?nsegs
  739.       ifdef @&class&_DATA
  740.         ?segname catstr @&class&_DATA
  741.         ?SetType %?&class&_DATA
  742.       elseifnb <class>
  743.         ?segname equ <class>
  744.         ?SetType type
  745.       endif
  746.       ?OpenSeg scope,class,model,type
  747.      endm
  748.  
  749. ;*** EndData - End data definitions
  750. ;
  751. ;   ENTRY
  752. ;    Same as above (although everything is optional)
  753. ;
  754.  
  755. EndData macro scope,class,model,type
  756.       ?CloseSeg scope,class,model,type,DefData
  757.       ?PopSeg %?nsegs
  758.      endm
  759.  
  760. ;*** DefCon - Define a constant
  761. ;
  762. ;   ENTRY
  763. ;    name    name of constant
  764. ;    val    value of constant
  765. ;
  766.  
  767. DefCon macro name,val
  768.      ?DefVar <equ>,name,val
  769.        endm
  770.  
  771. ;*** DefFn - Define function name(s)
  772. ;
  773. ;   ENTRY
  774. ;    name(s)     name(s) of function
  775. ;
  776.  
  777. DefFn macro n1,n2,n3,n4,n5,n6,n7,n8
  778.     irp n,<n1,n2,n3,n4,n5,n6,n7,n8>
  779.       ifnb <n>
  780.         if ?model EQ ?C
  781.           n equ <_&&n>
  782.         elseif ?model EQ ?PASCAL
  783.           if ?case
  784.         ?ToUpper n
  785.         % ifdif <n>,<?upper>
  786.           n catstr ?upper
  787.         endif
  788.           endif
  789.         endif
  790.         if ?declare EQ ?EXTRN
  791.           % ?DefExtrn n,near
  792.         elseif ?declare EQ ?PUBLIC
  793.           % ?DefPublic n
  794.         endif
  795.       endif
  796.     endm
  797.       endm
  798.  
  799. ;*** ?DefVar - Define a variable, with defaults
  800. ;
  801. ;   Used by DefType to create new type-macros, which simply
  802. ;   use this as the worker macro.
  803. ;
  804. ;   See ?DefMem for details.  All this macro does is substitute
  805. ;   the value of defaults (defval and defrep) for the other inputs.
  806.  
  807. ?DefVar macro    dtyp,var,val,defval,rep,defrep
  808.       ?t equ <var>
  809.       if ?nstrucs
  810.         ?nfields = ?nfields + 1
  811.       else
  812.         ifnb <var>
  813.           if ?model EQ ?C
  814.         ifndef var
  815.           var equ <_&var>
  816.           ?t catstr var
  817.         endif
  818.           elseif ?model EQ ?PASCAL
  819.         ifndef var
  820.           if ?case
  821.             ?ToUpper var
  822.             % ifdif <var>,<?upper>
  823.               var catstr ?upper
  824.             endif
  825.             ?t catstr ?upper
  826.           endif
  827.         endif
  828.           endif
  829.         endif
  830.       endif
  831.       ifb <val>
  832.         ifb <rep>
  833.           % ?DefMem <dtyp>,?t,<defval>,<defrep>,%?nfields
  834.         else
  835.           % ?DefMem <dtyp>,?t,<defval>,<rep>,%?nfields
  836.         endif
  837.       else
  838.         ifb <rep>
  839.           % ?DefMem <dtyp>,?t,<val>,<defrep>,%?nfields
  840.         else
  841.           % ?DefMem <dtyp>,?t,<val>,<rep>,%?nfields
  842.         endif
  843.       endif
  844.     endm
  845.  
  846. DEFdb    equ    <byte>        ;text-macros used by ?DefMem macro
  847. DEFdw    equ    <word>
  848. DEFdd    equ    <dword>
  849. DEFdf    equ    <fword>
  850. DEFdq    equ    <qword>
  851. DEFdt    equ    <tbyte>
  852. DEFequ    equ    <abs>
  853. DEFDB    equ    <byte>
  854. DEFDW    equ    <word>
  855. DEFDD    equ    <dword>
  856. DEFDF    equ    <fword>
  857. DEFDQ    equ    <qword>
  858. DEFDT    equ    <tbyte>
  859. DEFEQU    equ    <abs>
  860.  
  861. ;*** ?DefMem - Define actual storage
  862. ;
  863. ;   Used by ?DefVar to actually define a variable.
  864. ;
  865. ;   ENTRY
  866. ;    dtyp    the type declarator (db, structure name, etc)
  867. ;    var    variable name
  868. ;    val    an initial value; 0 if unspecified
  869. ;    rep    a repeat count; 1 if unspecified (ie, # elements)
  870. ;    fn    field number, if within a structure definition
  871.  
  872. ?DefMem macro dtyp,var,val,rep,fn
  873.       ?fStruc = 1
  874.       irp x,<db,dw,dd,df,dq,dt,equ>
  875.         ifidni <dtyp>,<x>
  876.           ?fStruc = 0
  877.         endif
  878.       endm
  879.       if ?declare EQ ?EXTRN
  880.         if ?nstrucs EQ 0
  881.           ifnb <var>
  882.         if ?fStruc
  883.           % ?DefExtrn var,byte
  884.         else
  885.           % ?DefExtrn var,%DEF&dtyp
  886.         endif
  887.           endif
  888.         endif
  889.       endif
  890.       ?fExtrn = 0
  891.       ifnb <var>
  892.         ?fExtrn = (.type var) and 80h
  893.       endif
  894.       if ?nstrucs
  895.         ?DefField fn
  896.       endif
  897.       if ?fExtrn EQ 0
  898.         if ?fStruc
  899.           if ?nstrucs
  900.         ifb <rep>
  901.           ?DefField fn,var,<db size dtyp dup(?)>
  902.         else
  903.           ?DefField fn,var,<db size dtyp * rep dup(?)>
  904.         endif
  905.         ?fExtrn = 80h
  906.           endif
  907.         endif
  908.       endif
  909.       if ?fExtrn EQ 0
  910.         ifb <val>
  911.           ifb <rep>
  912.         ifb <dtyp>
  913.           ifnb <var>
  914.             if ?fStruc
  915.               % ?DefLabel var,byte
  916.             else
  917.               % ?DefLabel var,DEF&dtyp
  918.             endif
  919.           endif
  920.         else
  921.           if ?fStruc
  922.             ?Alloc var,dtyp,<<>>,1
  923.           else
  924.             if ?nstrucs EQ 0
  925.               ?Alloc var,dtyp,0,0
  926.             else
  927.               ?DefField fn,var,<dtyp 0>
  928.             endif
  929.           endif
  930.         endif
  931.           else
  932.         if ?fStruc
  933.           ?Alloc var,dtyp,<rep dup(<>)>,1
  934.         else
  935.           if ?nstrucs EQ 0
  936.             ?Alloc var,dtyp,<rep dup(0)>,0
  937.           else
  938.             ?DefField fn,var,<dtyp rep dup(0)>
  939.           endif
  940.         endif
  941.           endif
  942.         else
  943.           ifb <rep>
  944.         if ?fStruc
  945.           ?Alloc var,dtyp,<<val>>,1
  946.         else
  947.           if ?nstrucs EQ 0
  948.             ?Alloc var,dtyp,<val>,0
  949.           else
  950.             ?DefField fn,var,<dtyp val>
  951.           endif
  952.         endif
  953.           else
  954.         if ?fStruc
  955.           ?Alloc var,dtyp,<rep dup(<val>)>,1
  956.         else
  957.           if ?nstrucs EQ 0
  958.             ?Alloc var,dtyp,<rep dup(val)>,0
  959.           else
  960.             ?DefField fn,var,<dtyp rep dup(val)>
  961.           endif
  962.         endif
  963.           endif
  964.         endif
  965.       endif
  966.       if ?declare EQ ?PUBLIC
  967.         if ?nstrucs EQ 0
  968.           ifnb <var>
  969.         % ?DefPublic var
  970.           endif
  971.         endif
  972.       endif
  973.     endm
  974.  
  975. endif ; INCL_DEF
  976.  
  977. ;*** Break - break a listing and give new subtitle
  978. ;
  979. ;   ENTRY   subtitle = new subtitle to use
  980. ;
  981. ;   EXIT    listing starts on new page with new subtitle
  982.  
  983. Break    macro    subtitle
  984.     subttl    subtitle
  985.     ifdef NOPAGE
  986.         page 255
  987.     else
  988.         page
  989.     endif
  990. endm
  991.  
  992. F16PRE_ equ    <f_>        ; far16 label prefix
  993. F32PRE_ equ    <g_>        ; far32 label prefix
  994. HYBPRE_ equ    <h_>        ; faronly label prefix
  995.  
  996. ;*** Procedure - declares a procedure
  997. ;
  998. ;   This produces the appropriate "proc" and "public" pseudo ops
  999. ;   and initializes a number of global symbols used by ArgVar,
  1000. ;   LocalVar, EnterProc, SaveReg, RestoreReg, LeaveProc, and
  1001. ;   EndProc.  Procedures may not nest; nesting will cause assembler
  1002. ;   errors.  If declared hybrid or faronly, a far 16 bit procedure,
  1003. ;   HYBPRE_&name, is generated.  If declared far16, a far 32 bit procedure,
  1004. ;   F16PRE_&name, is generated.
  1005. ;
  1006. ;   ENTRY   name     = name of procedure
  1007. ;        distance = "near" - a near procedure can be called
  1008. ;               with the "call" instruction.
  1009. ;             = "far" - a far procedure can be called with
  1010. ;               the "call" instruction.  Can't be combined.
  1011. ;             = "hybrid" - a hybrid procedure can be
  1012. ;               called with the "call" instruction (for near
  1013. ;               call) or the CALLFAR macro (for far call).
  1014. ;               Same as <near,faronly>.    Can only be used
  1015. ;               in 16 bit code.
  1016. ;             = "faronly" - a faronly procedure can
  1017. ;               only be called with the CALLFAR macro.
  1018. ;               Can only be used in 16 bit code.
  1019. ;             = blank - defaults to near
  1020. ;             = "far16" - 16 bit procedure that can be called
  1021. ;               far by 32-bit code (via the CALL16 macro).
  1022. ;               Can only be used in 16 bit code.
  1023. ;             If in a 16 bit code segment,
  1024. ;             <near,far16,faronly,hybrid> may be combined.
  1025. ;        scope    = "local" - don't make "name" public
  1026. ;             = "farlocal" - hybrid procedure will have far
  1027. ;               local and near public attribute.
  1028. ;             = "nearlocal" - hybrid procedure will have near
  1029. ;               local and far public attributes.
  1030. ;             = blank - defaults to public for both near and
  1031. ;               far attributes.
  1032. ;     treg  scratch register - OBSOLETE!!
  1033. ;        If non-blank, this register is used to optimizize far calls
  1034. ;        to hybrid procedures, at the expense of near calls.
  1035. ;        By default, near calls are the more efficient of the two.
  1036. ;     abase  the number of bytes to skip for calculating the ArgVar
  1037. ;         offsets. The default (if this is blank) depends on the
  1038. ;         "distance" variable.  16 bit "NEAR" is 4 and "FAR" is 6.
  1039. ;         If set to the string "ESP", then ArgVar uses ESP instead
  1040. ;         of [E]BP to refer to parameters on the stack, and assumes
  1041. ;         that [E]BP is not saved on the stack.  LocalVar, EnterProc,
  1042. ;         and LeaveProc are then illegal to use within the procedure.
  1043. ;
  1044. ;        ?argfar = 0 - ok to use ArgVar in this procedure
  1045. ;            = 4 - need special care using ArgVar.  Also used
  1046. ;              by user as a suffix to access arguments
  1047. ;              pushed by far callers.  See example at top.
  1048. ;              near+faronly (or hybrid)
  1049. ;            = 8 - need special care using ArgVar.  near+far16
  1050. ;            = -1 - Don't use ArgVar.  near+far16+faronly
  1051.  
  1052. ?frame         =    0    ; initial
  1053. ?aframe      =    0    ; initial
  1054. ?abase         =    0    ; initial
  1055. ?stackdepth  =    0    ; initial stack size
  1056. ?initstack   =    0    ; initial stack size
  1057. ?local         =    0    ; local proc flag
  1058. ?distance    =    0    ; near/far, 16/32 bit, faronly, bpframe distance flags
  1059. ?olddistance =    0    ; outer scope distance flags
  1060. ?depth         =    0    ; procedure nesting level
  1061. ?argfar      =    0    ; ok to use ArgVar in procedure
  1062.  
  1063. ; ?distance variable bit fields:
  1064. ?PD_NEAR    equ    0001h    ; callable near (16 or 32 bit)     "name"
  1065. ?PD_FAR     equ    0002h    ; 16-bit far routine         "name"
  1066. ?PD_FARONLY    equ    0004h    ; callable through CALLFAR macro "HYBPRE_&name"
  1067. ?PD_FAR16    equ    0008h    ; 16-bit callable from 32-bit     "F16PRE_&name"
  1068. ?PD_FAR32    equ    0010h    ; 32-bit callable from 16-bit     "F32PRE_&name"
  1069. ?PD_ESPFRAME    equ    0020h    ; uses ESP ArgVar frame
  1070. ?PD_ENTERED    equ    0040h    ; EnterProc seen
  1071. ?PD_DIST    equ    0080h    ; distance arg seen
  1072. ?PD_CDECL    equ    0100h    ; cdecl seen
  1073. ?PD_PASCAL    equ    0200h    ; pascal seen
  1074.  
  1075. ?PD_DISTMASK    equ    (?PD_NEAR+?PD_FAR+?PD_FARONLY+?PD_FAR16+?PD_FAR32)
  1076.  
  1077. ; ?local variable bit fields:
  1078. ?LC_NEARLOCAL    equ    0001h    ; near label is local
  1079. ?LC_FARLOCAL    equ    0002h    ; faronly label is local
  1080. ?LC_FAR16LOCAL    equ    0004h    ; far16 label is local
  1081. ?LC_FAR32LOCAL    equ    0008h    ; far32 label is local
  1082. ?LC_LOCAL    equ    0010h    ; all labels are local
  1083.  
  1084. ProcError macro msg
  1085. %   %out @FileName.asm: Error in unknown Procedure: msg
  1086. endm
  1087.  
  1088. CatPrefix macro before, prefix, name, after
  1089.     .lall
  1090.     before prefix&name after
  1091.     .xall
  1092. endm
  1093.  
  1094. RETC macro n
  1095.     ?bm1 = ?aframe        ;; assume new C calling convention (or pascal)
  1096.     if (?distance and ?PD_CDECL)
  1097.     ?bm1 = 0        ;; oops, cdecl - don't clean off args
  1098.     endif
  1099.     ifnb <n>
  1100.     ?bm1 = n
  1101.     endif
  1102.     ?Eval RETP,%?bm1
  1103. endm
  1104.  
  1105. Procedure macro   name,distance,scope,treg,abase,blank
  1106. ifdef ALIGNCODE
  1107.     align 4
  1108. endif
  1109.     ProcError macro msg
  1110. %    %out @FileName.asm: Error in Procedure name: msg
  1111.     endm
  1112.     if2
  1113.     ifnb <treg>
  1114.         ProcError <treg_arg must be _blank: treg>
  1115.         .err
  1116.     endif
  1117.     ifnb <blank>
  1118.         ProcError <Too many parameters>
  1119.         .err
  1120.     endif
  1121.     if ?depth gt 1
  1122.         ProcError <Nesting too deep>
  1123.         .err
  1124.     endif
  1125.     endif
  1126.     ?depth     = ?depth + 1
  1127.     ?olddistance = ?distance    ;; save previous value
  1128.     ?frame     = 0
  1129.     ?aframe     = 0
  1130.     ?initstack     = ?stackdepth    ;; beginning of procedure
  1131.     ?local     = 0        ;; default to public
  1132.     ?distance     = 0        ;; default is set elsewhere
  1133.     ?argfar     = 0        ;; okay to use ArgVar
  1134.     ?nfields     = 0        ;; used here to count ArgVars
  1135.     ?name     equ <name>    ;; save current procedure name
  1136.     ?wdsz     = 2        ;; default word size
  1137.     if (?cstype eq ?CS_32bit)
  1138.     ?wdsz = 4
  1139.     endif
  1140.     ifnb <scope>
  1141.     irp x,<scope>
  1142.         ifidni <x>,<nearlocal>        ;; near is local
  1143.         ?local = ?local or ?LC_NEARLOCAL
  1144.         elseifidni <x>,<far16local>     ;; far16 is local
  1145.         ?local = ?local or ?LC_FAR16LOCAL
  1146.         elseifidni <x>,<far32local>     ;; far16 is local
  1147.         ?local = ?local or ?LC_FAR32LOCAL
  1148.         elseifidni <x>,<farlocal>        ;; faronly is local
  1149.         ?local = ?local or ?LC_FARLOCAL
  1150.         elseifidni <x>,<local>        ;; all are local
  1151.         ?local = ?local or ?LC_NEARLOCAL or ?LC_FARLOCAL \
  1152.                 or ?LC_FAR16LOCAL or ?LC_FAR32LOCAL \
  1153.                 or ?LC_LOCAL
  1154.         elseif2
  1155.         ProcError <Bad scope_arg: x>
  1156.         .err
  1157.         endif
  1158.     endm
  1159.     endif
  1160.     .lall
  1161.     ?bm1 = ?local                ;; only for listing files
  1162.     .xall
  1163.  
  1164.     ifnb <distance>
  1165.     irp x,<distance>
  1166.         ifidni <x>,<near>        ;; is near
  1167.         ?distance = ?distance or ?PD_NEAR or ?PD_DIST
  1168.         elseifidni <x>,<far16>    ;; is 16 bit callable from 32
  1169.         ?distance = ?distance or ?PD_FAR16 or ?PD_DIST
  1170.         elseifidn <x>,<far32>    ;; is 32 bit callable from 16
  1171.         ?distance = ?distance or ?PD_FAR32 or ?PD_DIST
  1172.         elseifidni <x>,<far>    ;; is 16 bit far
  1173.         ?distance = ?distance or ?PD_FAR or ?PD_DIST
  1174.         elseifidni <x>,<faronly>    ;; is 16 bit faronly
  1175.         ?distance = ?distance or ?PD_FARONLY or ?PD_DIST
  1176.         elseifidni <x>,<hybrid>    ;; is 16-bit near/faronly hybrid
  1177.         ?distance = ?distance or ?PD_NEAR or ?PD_FARONLY or ?PD_DIST
  1178.         elseifidn <x>,<cdecl>    ;; is cdecl (caller cleanup)
  1179.         ?distance = ?distance or ?PD_CDECL
  1180.         elseifidn <x>,<pascal>    ;; is pascal (callee cleanup)
  1181.         ?distance = ?distance or ?PD_PASCAL
  1182.         elseif2
  1183.         ProcError <Bad distance_arg: x>
  1184.         .err
  1185.         endif
  1186.     endm
  1187.  
  1188.     ;; If both types of 16 bit thunks are required, add a near
  1189.     ;; procedure body, and have both thunks call it near:
  1190.  
  1191.     if ((?distance and ?PD_DISTMASK) eq (?PD_FAR16 or ?PD_FARONLY))
  1192.         ?distance = ?distance or ?PD_NEAR
  1193.     endif
  1194.  
  1195.     if2
  1196.         ;; Disallow 16 bit thunks in 32 bit code.
  1197.  
  1198.         if (?cstype eq ?CS_32bit)
  1199.         if (?distance and (?PD_FAR16 or ?PD_FARONLY))
  1200.             ProcError <16-bit Procedure in 32-bit code>
  1201.             .err
  1202.         endif
  1203.         else
  1204.         if (?distance and ?PD_FAR32)
  1205.             ProcError <32-bit Procedure in 16-bit code>
  1206.             .err
  1207.         endif
  1208.         endif
  1209.         if (?distance and ?PD_FAR)
  1210.         if ((?distance and ?PD_DISTMASK) ne ?PD_FAR)
  1211.             ProcError <distance_arg cannot use FAR combinations>
  1212.             .err
  1213.         endif
  1214.         endif
  1215.         if ((?distance and (?PD_CDECL or ?PD_PASCAL)) eq \
  1216.         (?PD_CDECL or ?PD_PASCAL))
  1217.  
  1218.         ProcError <pascal and cdecl conflict>
  1219.         .err
  1220.         endif
  1221.     endif
  1222.     endif
  1223.     if ((?distance and ?PD_DIST) eq 0)
  1224.     ?distance = ?distance or ?PD_NEAR    ;; default is near
  1225.     endif
  1226.     ifndef STDCALL
  1227.     if ((?distance and ?PD_PASCAL) eq 0)
  1228.         ?distance = ?distance or ?PD_CDECL    ;; force cdecl override
  1229.     endif
  1230.     endif
  1231.     .lall
  1232.     ?bm1 = ?distance                ;; only for listing files
  1233.     .xall
  1234.  
  1235.     RETP macro n                ;; use masm's default RET type
  1236.     ret n
  1237.     endm
  1238.  
  1239.     ;; if near, generate any needed thunks first
  1240.  
  1241.     if (?distance and ?PD_NEAR)
  1242.     if (?distance and ?PD_FAR16)        ;; if far16 thunk needed
  1243.         if (?distance and ?PD_FARONLY)    ;; and if faronly thunk needed,
  1244.         if (?local and ?LC_FARLOCAL)    ;; use call for faronly thunk
  1245.             GenHybrid name,<local>,<usecall>
  1246.         else
  1247.             GenHybrid name,,<usecall>
  1248.         endif
  1249.         endif
  1250.         if (?local and ?LC_FAR16LOCAL)    ;; far16 thunk falls through
  1251.         ?Gen16 name,local
  1252.         else
  1253.         ?Gen16 name
  1254.         endif
  1255.                         ;; far16 thunk not needed
  1256.     elseif (?distance and ?PD_FARONLY)    ;; if faronly thunk needed,
  1257.         if (?local and ?LC_FARLOCAL)    ;; faronly thunk falls through
  1258.         GenHybrid name,local
  1259.         else
  1260.         GenHybrid name
  1261.         endif
  1262.     elseif (?distance and ?PD_FAR32)    ;; if far32 thunk needed
  1263.         if (?local and ?LC_FAR32LOCAL)    ;; use call for far32 thunk
  1264.         GenFar32 name,local
  1265.         else
  1266.         GenFar32 name
  1267.         endif
  1268.     endif
  1269.     if (?local and ?LC_NEARLOCAL)        ;; generate main proc label
  1270.         GenPublic name,<local>,code
  1271.     else
  1272.         GenPublic name,,code
  1273.     endif
  1274.     name proc near                ;; main proc is near
  1275.     else
  1276.  
  1277.     ;; main proc isn't near; may need to prepend HYBPRE_, F16PRE_ or F32PRE_
  1278.  
  1279.     if (?distance and ?PD_FARONLY)
  1280.         if (?local and ?LC_FARLOCAL)    ;; generate proc HYBPRE_label
  1281.         ?PrePublic %HYBPRE_, name,<local>,code
  1282.         else
  1283.         ?PrePublic %HYBPRE_, name,,code
  1284.         endif
  1285.         CatPrefix , %HYBPRE_, <name>, <proc far> ;; main proc is far
  1286.     endif
  1287.     if (?distance and ?PD_FAR16)
  1288.         if (?local and ?LC_FAR16LOCAL)    ;; generate proc F16PRE_label
  1289.         ?PrePublic %F16PRE_, name,<local>,code
  1290.         else
  1291.         ?PrePublic %F16PRE_, name,,code
  1292.         endif
  1293.         CatPrefix , %F16PRE_, <name>, <proc far> ;; main proc is far
  1294.         RETP macro n            ;; use RETFD
  1295.         RETFD n
  1296.         endm
  1297.     endif
  1298.     if (?distance and ?PD_FAR32)
  1299.         if (?local and ?LC_FAR32LOCAL)    ;; generate proc F32PRE_label
  1300.         ?PrePublic %F32PRE_, name,<local>,code
  1301.         else
  1302.         ?PrePublic %F32PRE_, name,,code
  1303.         endif
  1304.         CatPrefix , %F32PRE_, <name>, <proc far> ;; main proc is far
  1305.     endif
  1306.     if (?distance and ?PD_FAR)
  1307.         if (?local and ?LC_LOCAL)        ;; generate main proc label
  1308.         GenPublic name,<local>,code
  1309.         else
  1310.         GenPublic name,,code
  1311.         endif
  1312.         name proc far            ;; main proc is far
  1313.     endif
  1314.     endif
  1315.  
  1316.     if (?distance and ?PD_NEAR)
  1317.     ?abase = 4 + 4            ;; ret address, EBP are 4 bytes each?
  1318.     if (?cstype ne ?CS_32bit)
  1319.         ?abase = 2 + 2        ;; ret address, BP are 2 bytes each?
  1320.     endif
  1321.     if (?distance and (?PD_FAR32 or ?PD_FAR16))
  1322.         ?argfar = 8         ;; extra 32 bit far call on stack
  1323.     endif
  1324.     if (?distance and ?PD_FARONLY)
  1325.         ife ?argfar
  1326.         ?argfar = 4        ;; extra 16 bit far call on stack
  1327.         else
  1328.         ?argfar = -1        ;; doesn't work when thunks combined
  1329.         endif
  1330.     endif
  1331.     else
  1332.     if (?distance and ?PD_FAR32)
  1333.         ?abase = 8 + 4        ;; ret addr is 8 bytes, EBP is 4 bytes!
  1334.     endif
  1335.     if (?distance and ?PD_FAR16)
  1336.         ?abase = 8 + 2        ;; ret addr is 8 bytes, BP is 2 bytes!
  1337.     endif
  1338.     if (?distance and ?PD_FARONLY)
  1339.         ?abase = 4 + 2        ;; ret addr is 4 bytes, BP is 2 bytes!
  1340.     endif
  1341.     if (?distance and ?PD_FAR)
  1342.         ?abase = 8 + 4        ;; ret addr is 8 bytes, EBP is 4 bytes?
  1343.         if (?cstype ne ?CS_32bit)
  1344.         ?abase = 4 + 2        ;; ret addr is 4 bytes, BP is 2 bytes!
  1345.         endif
  1346.     endif
  1347.     endif
  1348.     ifnb <abase>            ;; if abase is not blank, then use it
  1349.     ifidni <abase>,<esp>        ;; if abase is ESP, then no [E]BP frame
  1350.         ?abase = ?abase - 4     ;; uncompensate for EBP
  1351.         if (?cstype ne ?CS_32bit)
  1352.         ?abase = ?abase + 2    ;; oops.  uncompensate only for BP
  1353.         endif
  1354.         ?distance = ?distance or ?PD_ESPFRAME
  1355.     else
  1356.         ?abase = abase
  1357.     endif
  1358.     endif
  1359.     .lall
  1360.     ?bm1 = ?abase                ;; only for listing files
  1361.     ?bm1 = ?argfar                ;; only for listing files
  1362.     .xall
  1363. endm
  1364.  
  1365. ;*** EndProc - End a procedure
  1366. ;
  1367. ;   This ends a procedure declaration by generating appropriate
  1368. ;   endp pseudo ops. It also checks to make sure the number of
  1369. ;   registers saved with SaveReg are the same as the number of
  1370. ;   registers restored with RestoreReg within the procedure body.
  1371. ;   This check is not fool-proof because it assumes all the
  1372. ;   SaveReg and RestoreReg macros will be executed exactly once
  1373. ;   during run time, which may not be a valid assumption.
  1374. ;
  1375. ;   ENTRY   name = name of procedure to end
  1376. ;        chk  = blank - verify #registers saved by SaveReg
  1377. ;           and restored by RestoreReg are the same.
  1378. ;         = "NoCheck" - don't check
  1379. ;   (global var)
  1380. ;        ?depth     = level of Procedure nested.  Max is 1.
  1381. ;        ?distance     = set by Procedure macro
  1382. ;        ?olddistance = value of ?distance when Procedure macro
  1383. ;               was called.
  1384. ;
  1385. ;   EXIT    "endp" with appropriate label generated.
  1386. ;   (global variables)
  1387. ;        ?depth   = decremented
  1388. ;        ?distance = restored to previous value when
  1389. ;            Procedure macro was called.
  1390. ;
  1391. ;   SEE ALSO: Procedure, ArgVar, LocalVar, EnterProc, SaveReg,
  1392. ;          RestoreReg, LeaveProc, EndProc.
  1393.  
  1394. EndProc macro name, chk
  1395. ifdef ALIGNCODE
  1396.     align 4
  1397. endif
  1398.     if2
  1399.     if (?distance and ?PD_ENTERED)
  1400.         ifdif <chk>,<NoCheck>
  1401.         ProcError <EndProc invoked without LeaveProc>
  1402.         .err
  1403.         endif
  1404.     endif
  1405.     ife ?depth
  1406.         ProcError <EndProc without matching Procedure>
  1407.         .err
  1408.     endif
  1409.     ?bm1 = 0                ;; assume no NoCheck
  1410.     ifnb <chk>
  1411.         ifdif <chk>,<NoCheck>
  1412.         ProcError <EndProc: bad NoCheck arg: chk>
  1413.         .err
  1414.         else
  1415.         ?bm1 = 1            ;; saw NoCheck
  1416.         endif
  1417.     endif
  1418.     if (?bm1 eq 0)
  1419.         if (?initstack ne ?stackdepth)    ;; is it different?
  1420.         ProcError <SaveReg/RestoreReg mismatch>
  1421.         endif
  1422.     endif
  1423.     endif
  1424.     if (?distance and ?PD_NEAR)
  1425.     name endp            ;; procedure is near
  1426.     elseif (?distance and ?PD_FAR16)
  1427.     CatPrefix , %F16PRE_, <name>, <endp> ;; procedure is is far16
  1428.     elseif (?distance and ?PD_FAR32)
  1429.     CatPrefix , %F32PRE_, <name>, <endp> ;; procedure is is far32
  1430.     elseif (?distance and ?PD_FARONLY)
  1431.     CatPrefix , %HYBPRE_, <name>, <endp> ;; procedure is is faronly
  1432.     else
  1433.     name endp            ;; procedure is far
  1434.     endif
  1435.     ?depth = ?depth - 1
  1436.     ?distance = ?olddistance        ;; restore previous value
  1437.     ifdef KILLASSUMES
  1438.     assume ds:nothing, es:nothing, ss:nothing
  1439.     if (?cstype eq ?CS_32bit)
  1440.         assume fs:nothing, gs:nothing
  1441.     endif
  1442.     endif
  1443. ifdef ALIGNCODE
  1444.     align 4
  1445. endif
  1446. endm
  1447.  
  1448. ;*** GenPublic - generate a (unique) public label
  1449. ;
  1450. ;   Given a name, this macro tags a prefix of the form lxxx_
  1451. ;   (where xxx is a unique number) to it to form a unique public
  1452. ;   label labeling the current location. This is used for symbolic
  1453. ;   debugger support.
  1454. ;
  1455. ;   ENTRY   name  = name to be made public
  1456. ;        local = blank - simply make "name" into a public label
  1457. ;              without tagging a prefix
  1458. ;            anything else - tag a prefix unless NOLOCAL
  1459. ;              is defined.
  1460. ;   (global variables)
  1461. ;        NOLOCAL = if defined, make "name" into a public label
  1462. ;              without tagging a prefix regardless of what
  1463. ;              "local" is.
  1464. ;
  1465. ;   EXIT    "name" is declared public (with prefix attached if
  1466. ;        "local" is not blank or NOLOCAL is defined) and labels
  1467. ;        the current location.
  1468.  
  1469. GenPublic macro name,local,code        ;; generate a public or local symbol
  1470.     ifb <local>             ;; if local symbol not requested
  1471.     % ?DefPublic name
  1472.     else
  1473.     ifdef NOLOCAL            ;; if all symbols should be public
  1474.         % ?DefPublic name
  1475.     else
  1476.         % ?DefPublic @FileName&&$&name
  1477.         ifb <code>            ;; allow masm PUBDEF DS association
  1478.         % ?Eval @FileName&&$&name <label byte>
  1479.         else            ;; avoid masm PUBDEF DS association
  1480.         % ?Eval @FileName&&$&name::
  1481.         endif
  1482.     endif
  1483.     endif
  1484. endm
  1485.  
  1486. ?PrePublic macro prefix,name,local,code
  1487.     GenPublic prefix&name,<local>,<code>
  1488. endm
  1489.  
  1490. ;*** Entry - generate a near/hybrid/faronly entry into a procedure
  1491. ;
  1492. ;   This is used for creating additional entry points into a
  1493. ;   procedure.
  1494. ;
  1495. ;   ENTRY   name     = name of entry point
  1496. ;        distance = blank - create near entry point
  1497. ;             = "near" - create near entry point
  1498. ;             = "far" - create far entry point
  1499. ;             = "faronly" - create faronly entry point
  1500. ;             = "far16" - create far16 entry point
  1501. ;             = "hybrid" - create hybrid entry point
  1502. ;        scope    = blank - make entry point public
  1503. ;             = non-blank - if NOLOCAL is defined, the entry
  1504. ;                   point is still made public. Else
  1505. ;                   it is made local (fake local,
  1506. ;                   see the macro GENHYBRID).
  1507. ;        nocheck  = non-blank - defeat context checking
  1508. ;   (global var)
  1509. ;        NOLOCAL  = undefined - "scope" controls the scope of the
  1510. ;                   entry point
  1511. ;             = defined - make the entry point public
  1512. ;                 regardless of "scope."
  1513. ;
  1514. ;   EXIT    new entry point and "public" pseudo op generated.
  1515. ;
  1516. ;   SEE ALSO: Procedure
  1517.  
  1518. ?entrydistance = 0
  1519. Entry macro name,distance,scope,nocheck
  1520. local a
  1521.     ifnb <scope>
  1522.     if2
  1523.         ifdifi <local>,<scope>
  1524.         %out Bad scope_arg scope in Entry name
  1525.         .err
  1526.         endif
  1527.     endif
  1528.     endif
  1529.     ?entrydistance = ?PD_NEAR
  1530.     ifnb <distance>
  1531.     ifidni <distance>,<near>    ;; was it near?
  1532.         GenPublic name,<scope>    ;; generate a public or local symbol
  1533.         name::
  1534.     elseifidni <distance>,<far>    ;; was it far?
  1535.         ?entrydistance = ?PD_FAR
  1536.         GenPublic name,<scope>    ;; generate a public or local symbol
  1537.         name::
  1538.     elseifidni <distance>,<far16>    ;; was it far16?
  1539.         ?entrydistance = ?PD_FAR16
  1540.         ?PrePublic %F16PRE_, name,<scope> ;; generate a public/local symbol
  1541.         CatPrefix , %F16PRE_, <name>, <::>
  1542.     elseifidn <distance>,<far32>    ;; was it far32?
  1543.         ?entrydistance = ?PD_FAR32
  1544.         ?PrePublic %F32PRE_, name,<scope> ;; generate a public/local symbol
  1545.         CatPrefix , %F32PRE_, <name>, <::>
  1546.     elseifidni <distance>,<faronly> ;; was it faronly?
  1547.         ?entrydistance = ?PD_FARONLY
  1548.         if ((?distance and (?PD_FAR16 or ?PD_NEAR)) eq ?PD_FAR16)
  1549.         ?entrydistance = ?PD_FAR16
  1550.         jmp short a        ;; other callers skip faronly linkage
  1551.         endif
  1552.         ?PrePublic %HYBPRE_, name,<scope> ;; generate a public/local symbol
  1553.         CatPrefix , %HYBPRE_, <name>, <::>
  1554.         if ((?distance and (?PD_FAR16 or ?PD_NEAR)) eq ?PD_FAR16)
  1555.  
  1556.         ; If this is a FAR16 entry in a faronly procedure, munge
  1557.         ; the 16:16 return address so we can do a common RETFD.
  1558.  
  1559.         .386p
  1560.         push    dword ptr ss:[esp]    ; duplicate cs:ip on stack
  1561.         mov    word ptr ss:[esp+2],0    ; zero high word of new eip
  1562.         shr    dword ptr ss:[esp+4],16 ; move cs to low word
  1563.         CPUMode reset
  1564.         a::
  1565.         endif
  1566.     elseifidni <distance>,<hybrid>    ;; was it hybrid?
  1567.         jmp short name        ;; previous callers skip hybrid linkage
  1568.         GenHybrid name,<scope>
  1569.         GenPublic name,<scope>    ;; generate a public or local symbol
  1570.         name::
  1571.     else
  1572.         if2
  1573.         %out Bad distance_arg distance in Entry name
  1574.         .err
  1575.         endif
  1576.     endif
  1577.     else
  1578.     GenPublic name,<scope>        ;; generate a public or local symbol
  1579.     name::
  1580.     endif
  1581.     if2
  1582.     ifb <nocheck>
  1583.         if ((?distance and (?PD_NEAR or ?entrydistance)) ne ?entrydistance)
  1584.         %out Entry name not in distance context
  1585.         .err
  1586.         endif
  1587.         if (?entrydistance and (?PD_FARONLY or ?PD_FAR16))
  1588.         if (?cstype eq ?CS_32bit)    ;; invoked in 32 bit segment?
  1589.             ProcError <Entry name with distance context in 32 bit code>
  1590.             .err
  1591.         endif
  1592.         endif
  1593.     endif
  1594.     endif
  1595. endm
  1596.  
  1597. ;*** ArgVar - declare an argument (procedure parameter)
  1598. ;
  1599. ;   Assign "name" to an argument (pushed by caller) in the stack frame.
  1600. ;
  1601. ;   ENTRY   name     = name of argument
  1602. ;        length   = "BYTE"
  1603. ;             = "DBYTE" - double byte. Two new names
  1604. ;             "name&l" and "name&h" are created to refer
  1605. ;             to the low and high bytes.
  1606. ;             = "WORD"
  1607. ;             = "DWORD" - double word. Two new names
  1608. ;             "name&l" and "name&h" are created to refer
  1609. ;             to the low and high words.
  1610. ;             = a number - declare an argument of this
  1611. ;             length
  1612. ;        lowname  = if non-blank this is used instead of
  1613. ;               "name&l" when length is DBYTE.
  1614. ;        highname = if non-blank this is used instead of
  1615. ;               "name&h" when length is DBYTE.
  1616. ;        nowarn   = "hybrid" to stop ArgVar from generating a warning
  1617. ;               message about using ArgVar in a hybrid procedure.
  1618. ;               See example at top.
  1619. ;
  1620. ;   (global variables)
  1621. ;        ?aframe  = number of bytes declared as arguments so
  1622. ;               far. Set to 0 by Procedure.
  1623. ;        ?abase   = distance between BP and last byte of
  1624. ;               argument pushed. Usually 4 for near
  1625. ;               procedure and 6 for far.
  1626. ;        ?argfar  = 0 if ArgVars are at fixed offset from BP.
  1627. ;               This is the case for near, far, faronly and far16.
  1628. ;             = 4 if ArgVars are at different offset from BP
  1629. ;               depending on whether the procedure is called near
  1630. ;               or called far.  This is the case for near
  1631. ;               + faronly procedures (hybrid).
  1632. ;             = 8 if ArgVars are at different offset from BP
  1633. ;               depending on whether the procedure is called near
  1634. ;               or called 32 bit far.  This is the case for near
  1635. ;               + far16 procedures.
  1636. ;             = -1 if multiple thunks exist; ArgVars are broken.
  1637. ;
  1638. ;   EXIT    name EQU to the appropriate location in the stack
  1639. ;        frame (uses BP).
  1640. ;
  1641. ;        (global variables)
  1642. ;         ?aframe = incremented by number of bytes specified
  1643. ;              in "length".
  1644. ;
  1645. ;   NOTES   In 16 bit code segments argvars are word aligned and in
  1646. ;        32 bit code segments argvars are dword aligned.
  1647. ;
  1648. ;   SEE ALSO: Procedure, EnterProc, LeaveProc, EndProc.
  1649.  
  1650. ArgVar    macro    name,length,lowname,highname,nowarn
  1651.     if2
  1652.     if ?argfar eq -1
  1653.         ProcError <ArgVar cannot be used with multiple thunks>
  1654.         .err
  1655.     endif
  1656.     ifidni <nowarn>,<hybrid>
  1657.         ife ?argfar
  1658.         ProcError <ArgVar <nowarn> parameter invalid>
  1659.         .err
  1660.         endif
  1661.     else
  1662.         if ?argfar
  1663.         ProcError <references to ArgVar name may fail when called far>
  1664.         .err
  1665.         endif
  1666.     endif
  1667.     if (?distance and ?PD_ENTERED)
  1668.         ProcError <ArgVar name invoked inside EnterProc>
  1669.         .err
  1670.     endif
  1671.     endif
  1672.     if ?model EQ ?PASCAL
  1673.     ?nfields = ?nfields + 1
  1674.     ?MArg ArgVar,<name,length,lowname,highname,nowarn>,%?nfields
  1675.     else
  1676.     if (?distance and ?PD_ESPFRAME)
  1677.         ?bp equ <ESP>
  1678.     else
  1679.         if (?cstype eq ?CS_32bit)
  1680.         ?bp equ <EBP>
  1681.         else
  1682.         ?bp equ <BP>
  1683.         endif
  1684.     endif
  1685.     ?bm1 = ?aframe + ?abase
  1686.     ifidni <length>,<byte>
  1687.         ?aframe = ?aframe + 1
  1688.         ?BPEqu name,byte,%?bp,+,%?bm1
  1689.     elseifidni <length>,<dbyte>
  1690.         ?aframe = ?aframe + 2
  1691.         ?BPEqu name,word,%?bp,+,%?bm1
  1692.         ifb <lowname>
  1693.         ?BPEqu name&l,byte,%?bp,+,%?bm1
  1694.         else
  1695.         ?BPEqu lowname,byte,%?bp,+,%?bm1
  1696.         endif
  1697.         ifb <highname>
  1698.         ?BPEqu name&h,byte,%?bp,+,%(?bm1+1)
  1699.         else
  1700.         ?BPEqu highname,byte,%?bp,+,%(?bm1+1)
  1701.         endif
  1702.     elseifidni <length>,<word>
  1703.         ?aframe = ?aframe + 2
  1704.         ?BPEqu name,word,%?bp,+,%?bm1
  1705.     elseifidni <length>,<dword>
  1706.         ?aframe = ?aframe + 4
  1707.         ?BPEqu  name,dword,%?bp,+,%?bm1
  1708.         ?BPEqu  name&l,word,%?bp,+,%?bm1
  1709.         ?BPEqu  name&h,word,%?bp,+,%(?bm1+2)
  1710.     elseifidni <length>,<fword>
  1711.         ?aframe = ?aframe + 8
  1712.         ?BPEqu  name,fword,%?bp,+,%?bm1
  1713.         ?BPEqu  name&l,dword,%?bp,+,%?bm1
  1714.         ?BPEqu  name&h,dword,%?bp,+,%(?bm1+4)
  1715.     elseifdef ?&length
  1716.         ?aframe = ?aframe + ?&length
  1717.         if ?&length EQ 1
  1718.           ?BPEqu  name,byte,%?bp,+,%?bm1
  1719.         elseif ?&length EQ 2
  1720.           ?BPEqu  name,word,%?bp,+,%?bm1
  1721.         elseif ?&length EQ 4
  1722.           ?BPEqu  name,dword,%?bp,+,%?bm1
  1723.         else
  1724.           ?BPEqu  name,,%?bp,+,%?bm1
  1725.         endif
  1726.     else
  1727.         ?aframe = ?aframe + length
  1728.         ?BPEqu  name,byte,%?bp,+,%?bm1
  1729.     endif
  1730.     if (?cstype eq ?CS_32bit)        ;; align arguments
  1731.         if ?aframe and 03h
  1732.         ?aframe = (?aframe and (not 03h)) + 04h
  1733.         endif
  1734.     else
  1735.         if ?aframe and 01h
  1736.         ?aframe = ?aframe + 1
  1737.         endif
  1738.     endif
  1739.     endif
  1740. endm
  1741.  
  1742. ;*** LocalVar - declare a local variable
  1743. ;
  1744. ;   Reserves space on the stack frame for a local variable.
  1745. ;
  1746. ;   ENTRY   name     = name of local variable
  1747. ;        length   = "BP" - special case, no space is allocated,
  1748. ;             "name" labels the location where the old
  1749. ;             BP is stored.
  1750. ;             = "BYTE" - reserves a byte
  1751. ;             = "DBYTE" - reserves two bytes. Two additional
  1752. ;             names "name&l" and "name&h" are created to
  1753. ;             refer to the low and high byte.
  1754. ;             = "WORD" - reserves a word
  1755. ;             = "DWORD" - reserves a double word (4 bytes).
  1756. ;             Two additional names "name&l" and "name&h"
  1757. ;             are created to refer to the low and high
  1758. ;             word. This is always padded and not
  1759. ;             affected by "pad".
  1760. ;             = a number - reserves this many bytes.
  1761. ;        lowname  = if non-blank and "length" is "DBYTE", then
  1762. ;               this is used instead of "name&l".
  1763. ;        highname = if non-blank and "length" is "DBYTE", then
  1764. ;               this is used instead of "name&h".
  1765. ;        pad      = "PAD" - make WORD, DWORD, and numeric length
  1766. ;             variables start on even address.
  1767. ;             = "NOPAD" - don't pad WORD variables, but pad
  1768. ;             DWORD variables.
  1769. ;             = anything else - pad WORD and DWORD
  1770. ;             variables. Don't pad numeric length
  1771. ;             variables.
  1772. ;   (global variables)
  1773. ;        ?frame = number of bytes reserved as local var
  1774. ;             (including padding) so far; set to 0 by
  1775. ;             Procedure.
  1776. ;
  1777. ;   EXIT    "name" EQU to a reserved space in the stack frame (uses
  1778. ;        BP register). No executable code is generated.
  1779. ;   (global variables)
  1780. ;        ?pad   = don't care; should really be a local symbol
  1781. ;        ?nopad = don't care; should really be a local symbol
  1782. ;        ?frame = incremented by the number of bytes reserved
  1783. ;             as local var.
  1784. ;
  1785. ;   SEE ALSO: Procedure, EnterProc, LeaveProc, EndProc.
  1786.  
  1787. LocalVar macro    name,length,lowname,highname,pad
  1788. ifdef ALIGNCODE
  1789. align 4
  1790. endif
  1791.     if2
  1792.     if (?distance and ?PD_ESPFRAME)
  1793.         ProcError <LocalVar name invoked with ESP frame>
  1794.         .err
  1795.     endif
  1796.     if (?distance and ?PD_ENTERED)
  1797.         ProcError <LocalVar name invoked inside EnterProc>
  1798.         .err
  1799.     endif
  1800.     endif
  1801.     ?pad = 0
  1802.     ?nopad = 0
  1803.     ifidni <pad>,<PAD>
  1804.     ?pad = 1
  1805.     endif
  1806.     ifidni <pad>,<NOPAD>
  1807.     ?nopad = 1
  1808.     endif
  1809.     if (?cstype eq ?CS_32bit)
  1810.     ?bp equ <EBP>
  1811.     else
  1812.     ?bp equ <BP>
  1813.     endif
  1814.     ifidni <length>,<BP>    ;; makes a variable point to the old BP
  1815.     name EQU  (WORD PTR [BP])
  1816.     elseifidni <length>,<EBP>    ;; makes a variable point to the old EBP
  1817.     name EQU  (DWORD PTR [EBP])
  1818.     elseifidni <length>,<BYTE>
  1819.     ?frame =  ?frame + 1
  1820.     ?bm1 = ?frame
  1821.     ?BPEqu    name,byte,%?bp,-,%?bm1
  1822.     elseifidni <length>,<DBYTE>
  1823.     if ?frame and 1
  1824.         ?frame = ?frame + 1
  1825.     endif
  1826.     ?frame =  ?frame + 2
  1827.     ?bm1 = ?frame
  1828.     ?BPEqu    name,word,%?bp,-,%?bm1
  1829.     ifb <lowname>
  1830.         ?BPEqu  name&l,byte,%?bp,-,%?bm1
  1831.     else
  1832.         ?BPEqu  lowname,byte,%?bp,-,%?bm1
  1833.     endif
  1834.     ifb <highname>
  1835.         ?BPEqu  name&h,byte,%?bp,-,%(?bm1-1)
  1836.     else
  1837.        ?BPEqu  highname,byte,%?bp,-,%(?bm1-1)
  1838.     endif
  1839.     elseifidni <length>,<WORD>
  1840.     ife ?nopad
  1841.         if ?frame and 1
  1842.         ?frame = ?frame + 1
  1843.         endif
  1844.     endif
  1845.     ?frame =  ?frame + 2
  1846.     ?bm1 = ?frame
  1847.     ?BPEqu    name,word,%?bp,-,%?bm1
  1848.     elseifidni <length>,<DWORD>
  1849.     if ?frame and 1
  1850.         ?frame = ?frame + 1
  1851.     endif
  1852.     ?frame =  ?frame + 4
  1853.     ?bm1 = ?frame
  1854.     ?BPEqu    name,dword,%?bp,-,%?bm1
  1855.     ?BPEqu    name&l,word,%?bp,-,%?bm1
  1856.     ?BPEqu    name&h,word,%?bp,-,%(?bm1-2)
  1857.     elseifidni <length>,<FWORD>
  1858.     if ?frame and 1
  1859.         ?frame = ?frame + 1
  1860.     endif
  1861.     ?frame =  ?frame + 8
  1862.     ?bm1 = ?frame
  1863.     ?BPEqu    name,fword,%?bp,-,%?bm1
  1864.     ?BPEqu    name&l,dword,%?bp,-,%?bm1
  1865.     ?BPEqu    name&h,dword,%?bp,-,%(?bm1-4)
  1866.     elseifdef ?&length
  1867.     if ?frame and 1
  1868.         ?frame = ?frame + 1
  1869.     endif
  1870.     ?frame =  ?frame + ?&length
  1871.     ?bm1 = ?frame
  1872.     if ?&length EQ 1
  1873.         ?BPEqu  name,byte,%?bp,-,%?bm1
  1874.     elseif ?&length EQ 2
  1875.         ?BPEqu  name,word,%?bp,-,%?bm1
  1876.     elseif ?&length EQ 4
  1877.         ?BPEqu  name,dword,%?bp,-,%?bm1
  1878.     else
  1879.         ?BPEqu  name,,%?bp,-,%?bm1
  1880.     endif
  1881.     else
  1882.     ?frame =  ?frame + length
  1883.     if ?pad
  1884.         if ?frame and 1
  1885.         ?frame = ?frame + 1
  1886.         endif
  1887.     endif
  1888.     ?bm1 = ?frame
  1889.     ?BPEqu    name,byte,%?bp,-,%?bm1
  1890.     endif
  1891. endm
  1892.  
  1893. ;*** EnterProc - generate code to set up stack frame
  1894. ;
  1895. ;   This should followed all the LocalVar's and before any other
  1896. ;   executable code in the procedure.
  1897. ;
  1898. ;   ENTRY   varlist = list of word or dword values for initializing
  1899. ;              localvar's declared with LocalVar's.
  1900. ;          each initializer must be in the following form:
  1901. ;        [<{word,dword},]{constant,register,address}[>]
  1902. ;          example:
  1903. ;        EnterProc <0,<dword, -1>,ax,eax,<word,ds>,<word,es:[di].field>>
  1904. ;        chk     = "NoCheck" - defeat context checking
  1905. ;        falignesp = "alignesp" - dword align ESP
  1906. ;
  1907. ;   (global variables)
  1908. ;        ?frame = number of bytes reserved as localvar's by LocalVar.
  1909. ;
  1910. ;   EXIT    code generated to set up the stack frame
  1911. ;   (global variables)
  1912. ;        ?frame = may be incremented by 1, 2 or 3 to start ESP on a
  1913. ;             word or dword boundary relative to the stack frame.
  1914. ;
  1915. ;   NOTE: OPTIMIZATION for 486/Pentium
  1916. ;      Although one might think that a hardware/microcode implementation
  1917. ;      would be faster than a software implementation,  The ENTER/LEAVE
  1918. ;      instructions on the 486 are slower than the equivalent sequence
  1919. ;      of simpler instructions.
  1920. ;
  1921. ;      Timings:
  1922. ;     ┌────────────────┬────┬──────────────┬───────────────┬───────────────┐
  1923. ;     │ Instruction    │size│ 386DX clocks │  486 clocks   │ Pentium clocks│
  1924. ;     ├────────────────┼────┼──────────────┼───────────────┼───────────────┤
  1925. ;     │ push ebp       │ 1  │       2       │   1       │    1       │
  1926. ;     │ mov  ebp,esp   │ 2  │       2       │   1 +1 penalty│    1       │
  1927. ;     │ add  esp,IMMED │ 3  │       7       │   3 +1 penalty│    3       │
  1928. ;     ├────────────────┼────┼──────────────┼───────────────┼───────────────┤
  1929. ;     │ enter           │ 4  │      10       │  14       │   11       │
  1930. ;     └────────────────┴────┴──────────────┴───────────────┴───────────────┘
  1931. ;
  1932. ;
  1933. ;   SEE ALSO: Procedure, LeaveProc, EndProc.
  1934.  
  1935. EnterProc   macro varlist, chk, falignesp, nularg
  1936.     if2
  1937.     ifnb <chk>
  1938.         ifdif <chk>,<NoCheck>
  1939.         ProcError <EnterProc: bad NoCheck arg: chk>
  1940.         .err
  1941.         endif
  1942.     elseif (?distance and ?PD_ENTERED)
  1943.         ProcError <EnterProc invoked twice>
  1944.         .err
  1945.     endif
  1946.     ifnb <falignesp>
  1947.         ifdif <falignesp>,<alignesp>
  1948.         ProcError <EnterProc: bad alignesp arg: falignesp>
  1949.         .err
  1950.         endif
  1951.     endif
  1952.     ifnb <nularg>
  1953.         ProcError <EnterProc: too many args: nularg>
  1954.         .err
  1955.     endif
  1956.     endif
  1957.     if ?model EQ ?PASCAL
  1958.       if ?nfields
  1959.     ?model = NULL
  1960.     rept ?nfields
  1961.       ?InvPrg <?AM>,%?nfields
  1962.       ?nfields = ?nfields - 1
  1963.     endm
  1964.     ?model = ?PASCAL
  1965.       endif
  1966.     endif
  1967.     ?distance = ?distance or ?PD_ENTERED
  1968.     if (?cstype eq ?CS_32bit)
  1969.     ?ax equ <EAX>
  1970.     ?bp equ <EBP>
  1971.     ?sp equ <ESP>
  1972.     else
  1973.     ?ax equ <AX>
  1974.     ?bp equ <BP>
  1975.     ?sp equ <SP>
  1976.     endif
  1977.     ?frame = (?frame + 1) and not 1    ;; make final frame even
  1978.     if (?cstype eq ?CS_32bit)
  1979.     ?frame = (?frame + 3) and not 3 ;; make final frame dword multiple
  1980.     endif
  1981.     ifdef ALIGNFRAME
  1982.     ;;    Force all LocalVar frames to dword multiple:
  1983.     ?frame = (?frame + 3) and not 3 ;; make final frame dword multiple
  1984.     endif
  1985.     if ?frame
  1986.     if2
  1987.         if (?distance and ?PD_ESPFRAME)
  1988.         ProcError <LocalVars used with ESP frame>
  1989.         .err
  1990.         endif
  1991.     endif
  1992.     ?Eval push %?bp         ;; else set up frame
  1993.     ?Eval mov  %?bp,%?sp
  1994.     ifb <varlist>            ;; if no LocalVars initialized
  1995.         ?Eval lea  %?sp,%?bp,-,%?frame
  1996.     else
  1997.         ?bm1 = ?frame
  1998.         irp var,<varlist>        ;; and push each value
  1999.         ?bm3 = 1
  2000.         irp token,<var>         ;; examine each token
  2001.             if (?bm3 eq 1)        ;; if first token is word,dword
  2002.             ?bm3 = 0
  2003.             ifidni <token>,<word>
  2004.                 ?bm2 = 2        ;; two byte initializer
  2005.                 ?bm3 = 2
  2006.             elseifidni <token>,<dword>
  2007.                 ?bm2 = 4        ;; four byte initializer
  2008.                 ?bm3 = 2
  2009.             endif
  2010.             elseif (?bm3 eq 2)        ;; if second token is seg reg
  2011.             irp x,<cs,ds,es,fs,gs,ss>
  2012.                 ifidni <x>,<token>
  2013.                 if (((?bm2 eq 2) and (?cstype eq ?CS_32bit)) or \
  2014.                     ((?bm2 eq 4) and (?cstype ne ?CS_32bit)))
  2015.                     db MI_OPERANDSIZE
  2016.                 endif
  2017.                 push  x
  2018.                 ?bm3 = 3
  2019.                 endif
  2020.             endm
  2021.             if (?bm3 eq 2)        ;; else is memory reference
  2022.                 if (?bm2 eq 2)
  2023.                 push  word ptr token
  2024.                 else
  2025.                 push  dword ptr token
  2026.                 endif
  2027.                 ?bm3 = 3
  2028.             endif
  2029.             elseif (?bm3 eq 3)        ;; if fourth token exists
  2030.             if2
  2031.                 ProcError <EnterProc: var: extra characters: token>
  2032.                 .err
  2033.             endif
  2034.             else            ;; else invalid token: ignore
  2035.             ?bm3 = 0
  2036.             endif
  2037.         endm
  2038.         ife ?bm3
  2039.             ?RegSize var        ;; ?bm2 == size
  2040.             push  var
  2041.         endif
  2042.         if2
  2043.             if ?bm1 lt ?bm2
  2044.             ProcError <EnterProc: too many args>
  2045.             .err
  2046.             endif
  2047.             if (?cstype eq ?CS_32bit)
  2048.             irp x,<cs,ds,es,fs,gs,ss>
  2049.                 ifidni <x>,<var>
  2050.                 ProcError <EnterProc: var is ambiguous: use word,dword override>
  2051.                 endif
  2052.             endm
  2053.             endif
  2054.         endif
  2055.         ?bm1 = ?bm1 - ?bm2
  2056.         endm
  2057.         if ?bm1            ;; if any left over, pad the stack
  2058.         if ((?bm1 eq ?wdsz) or (?bm1 eq 2 * ?wdsz))
  2059.             ?Eval push %?ax
  2060.             if ?bm1 eq (2 * ?wdsz)
  2061.             ?Eval push %?ax ;; if ?bm1 == (2 * ?wdsz), takes 2 bytes
  2062.             endif
  2063.         elseif (?bm1 eq 2)    ;; push ax takes 2 bytes (w/override)
  2064.             push  ax
  2065.         else            ;; lea instruction takes 3 bytes
  2066.             ?Eval lea  %?sp,%?bp,-,%?frame
  2067.         endif
  2068.         endif
  2069.     endif
  2070.     ifnb <falignesp>
  2071.         ?Eval and  %?sp,<not 3>
  2072.     endif
  2073.     else
  2074.     if2
  2075.         ifnb <varlist>        ;; better be blank
  2076.         ProcError <EnterProc: no LocalVars to initialize>
  2077.         .err
  2078.         endif
  2079.     endif
  2080.     if (?distance and ?PD_ESPFRAME) eq 0    ;; if not an ESP frame
  2081.         ?bm1 = 1                ;; generate a frame
  2082.         ifdef NONULLFRAMES            ;; if null frames suppressed
  2083.         if (?aframe eq 0)        ;; and no ArgVars given
  2084.             ifb <falignesp>        ;; and no alignesp
  2085.             ?bm1 = 0        ;; suppress the frame
  2086.             endif
  2087.         endif
  2088.         endif
  2089.         if (?bm1)                ;; if should generate a frame
  2090.         ?Eval push %?bp
  2091.         ?Eval mov  %?bp,%?sp
  2092.         ifnb <falignesp>
  2093.             ?Eval and  %?sp,<not 3>
  2094.         endif
  2095.         endif
  2096.     endif
  2097.     endif
  2098. endm
  2099.  
  2100. ?RegSize macro var
  2101.     ?bm2 = ?wdsz        ;; default initializer size
  2102.     irp x,<ax,bx,cx,dx,si,di,bp,sp>
  2103.     ifidni <x>,<var>
  2104.         ?bm2 = 2        ;; two byte initializer
  2105.     endif
  2106.     endm
  2107.     irp x,<eax,ebx,ecx,edx,esi,edi,ebp,esp>
  2108.     ifidni <x>,<var>
  2109.         ?bm2 = 4        ;; four byte initializer
  2110.     endif
  2111.     endm
  2112. endm
  2113.  
  2114. ;*** LeaveProc - generate code to remove stack frame
  2115. ;
  2116. ;   This does the opposite of EnterProc. Use this before returning
  2117. ;   from the procedure.
  2118. ;
  2119. ;   ENTRY   chk  = "NoCheck" - defeat context checking
  2120. ;
  2121. ;   EXIT    code generated to remove stack frame
  2122. ;
  2123. ;   SEE ALSO: Procedure, EnterProc, EndProc.
  2124.  
  2125. LeaveProc   macro chk
  2126.     if2
  2127.     if (?distance and ?PD_ENTERED) eq 0
  2128.        ifdif <chk>,<NoCheck>
  2129.         ProcError <LeaveProc invoked without EnterProc>
  2130.         .err1
  2131.         endif
  2132.     endif
  2133.     endif
  2134.     ?distance = ?distance and not ?PD_ENTERED
  2135.     if (?distance and ?PD_ESPFRAME) eq 0    ;; if not an ESP frame
  2136.     ifdef NONULLFRAMES            ;; if null frames suppressed
  2137.         if (?frame or ?aframe)        ;; if ArgVars or LocalVars used
  2138.         leave
  2139.         endif
  2140.     else                    ;; else generate null frames
  2141.       leave
  2142.     endif
  2143.     endif
  2144. endm
  2145.  
  2146. ;*** ExitProc - generate code to remove stack frame and return
  2147. ;
  2148. ;   This does the opposite of EnterProc, just like LeaveProc.  Use
  2149. ;   this instead of LeaveProc to ALSO generate an appropriate RET instruction.
  2150. ;
  2151. ;   ENTRY   "premature" to document a premature exit (optional)
  2152. ;
  2153. ;   EXIT    code generated to remove stack frame and return
  2154. ;
  2155. ;   SEE ALSO: Procedure, EnterProc, LeaveProc, EndProc.
  2156.  
  2157. ExitProc   macro  arg
  2158.     if (?distance and ?PD_ENTERED) ne 0     ;; if an EnterProc is active
  2159.       LeaveProc                 ;; do the LeaveProc automatically
  2160.       ifidni <arg>,<premature>
  2161.        ?distance = ?distance or ?PD_ENTERED ;; premature exits should leave
  2162.       endif                    ;; the EnterProc state "in force"
  2163.     endif
  2164.     % ifdef _&&?name                ;; try to determine if this is
  2165.       ?Eval RETP                ;; a C function -JTP
  2166.     else
  2167.       ?Eval RETP,%?aframe            ;; otherwise, do a PASCAL-style RET
  2168.     endif
  2169. endm
  2170.  
  2171. ;*** FallInto - Specify procedure to fall into
  2172. ;
  2173. ;   This makes documentation of "fall-through" code cleaner.  Use this
  2174. ;   macro to state where you expect to fall, and use FallFrom to state where
  2175. ;   you expected to fall from (OPTIONAL).
  2176. ;
  2177. ;   ENTRY   name = name of procedure to fall into
  2178. ;
  2179. ;   EXIT    NONE
  2180.  
  2181. FallInto    macro   name
  2182.     ifnb <name>
  2183.       if1
  2184.     % ?name&&_end = $
  2185.       endif
  2186.       if2
  2187.     ifndef name
  2188.       %out FallInto:  name unknown
  2189.     else
  2190.       % if ?name&&_end NE ?segname:-1
  2191.         if (name-$ NE 0 and name-$ NE 1 and name-$ NE 2 and name-$ NE 3)
  2192.           % %out FallInto:    name does not follow ?name
  2193.           .err
  2194.         endif
  2195.       endif
  2196.     endif
  2197.       endif
  2198.     endif
  2199. ifdef ALIGNCODE
  2200.     align 4
  2201. endif
  2202. endm
  2203.  
  2204. ;*** FallFrom - Verify that we fell from the specified procedure
  2205. ;
  2206. ;   This makes documentation of "fall-through" code cleaner.  Use FallInto
  2207. ;   to state where you expect to fall (MANDATORY), and use this macro to
  2208. ;   state where you expected to fall from.
  2209. ;
  2210. ;   ENTRY   name = name of procedure fell from
  2211. ;
  2212. ;   EXIT    code generated to remove stack frame and return
  2213.  
  2214. FallFrom    macro   name
  2215.     ifnb <name>
  2216.       ifdef name&_end
  2217.     if (name&_end NE $ and name&_end NE $-1 and  name&_end NE $-2 and name&_end NE $-3)
  2218.       if1
  2219.         % %out FallFrom:  name does not precede ?name
  2220.       endif
  2221.       % name&_end = ?segname:-1
  2222.       .err
  2223.     endif
  2224.       else
  2225.     if1
  2226.       %out FallFrom:  name unknown
  2227.     endif
  2228.       endif
  2229.     endif
  2230. ifdef ALIGNCODE
  2231.     align 4
  2232. endif
  2233. endm
  2234.  
  2235. ;*** SaveReg - generate code to save registers on stack
  2236. ;
  2237. ;   Use with macros Procedure, ArgVar, LocalVar, EnterProc,
  2238. ;   RestoreRegs, LeaveProc, and EndProc.
  2239. ;
  2240. ;   ENTRY   reglist = list of registers to save
  2241. ;   (global variables)
  2242. ;        ?stackdepth = #items pushed on the stack in the
  2243. ;              current procedure. Used for error
  2244. ;              checking in the EndProc macro.
  2245. ;
  2246. ;   EXIT    code generated to push registers on the stack.
  2247. ;   (global variables)
  2248. ;        ?stackdepth = incremented once for each register saved.
  2249. ;
  2250. ;   SEE ALSO: Procedure, RestoreReg, EndProc.
  2251.  
  2252. SaveReg macro    reglist     ;; push those registers
  2253.     irp reg,<reglist>
  2254.     ?RegSize reg
  2255.     ?stackdepth = ?stackdepth + ?bm2
  2256.       push reg
  2257.     endm
  2258. endm
  2259.  
  2260. ;*** RestoreReg - generate code to restore registers from the stack
  2261. ;
  2262. ;   Use with macros Procedure, ArgVar, LocalVar, EnterProc,
  2263. ;   SaveReg, LeaveProc, and EndProc.
  2264. ;
  2265. ;   ENTRY   reglist = list of registers to restore. The order of
  2266. ;              registers specfied must be the reverse of
  2267. ;              that specified in SaveReg.
  2268. ;   (global variables)
  2269. ;        ?stackdepth = #items pushed on the stack in the
  2270. ;              current procedure. Used for error
  2271. ;              checking in the EndProc macro.
  2272. ;
  2273. ;   EXIT    code generated to pop registers.
  2274. ;   (global variables)
  2275. ;        ?stackdepth = decremented once for each register
  2276. ;              restored.
  2277. ;
  2278. ;   SEE ALSO: Procedure, SaveReg, EndProc.
  2279.  
  2280. RestoreReg  macro   reglist    ;; pop those registers
  2281.     irp reg,<reglist>
  2282.     ?RegSize reg
  2283.     ?stackdepth = ?stackdepth - ?bm2
  2284.       pop reg
  2285.     endm
  2286. endm
  2287.  
  2288. ;*** CPUMode - put a wrapper around .processor directives
  2289. ;
  2290.  
  2291. CPUMode macro cpu
  2292.     ifidn <cpu>,<8086>
  2293.     ?cpumode = 8086
  2294.     .8086
  2295.     elseifidn <cpu>,<8088>
  2296.     ?cpumode = 8086
  2297.     .8086
  2298.     elseifidn <cpu>,<286>
  2299.     ?cpumode = 286
  2300.     .286p
  2301.     elseifidn <cpu>,<386>
  2302.     ?cpumode = 386
  2303.     .386p
  2304.     elseifidni <cpu>,<reset>
  2305.     if ?cpumode eq 386
  2306.         .386p
  2307.     elseif ?cpumode eq 286
  2308.         .286p
  2309.     elseif ?cpumode eq 8086
  2310.         .8086
  2311.     endif
  2312.     else
  2313.     %out Unknown processor type cpu
  2314.     .err
  2315.     endif
  2316. endm
  2317.  
  2318. ;*** CallFn - Determine function type and call it
  2319. ;
  2320. ;   Invoke CCall if "_name" is defined;  otherwise, use PCall.
  2321. ;
  2322.  
  2323. CallFn    macro    name,arglst
  2324.       ifdef ?&name
  2325.         ifdef _&name
  2326.           CCall name,<arglst>
  2327.         else
  2328.           PCall name,<arglst>
  2329.         endif
  2330.       else
  2331.         if1
  2332.           %out CallFn name:  No prototype
  2333.         endif
  2334.         .err
  2335.       endif
  2336.     endm
  2337.  
  2338.  
  2339. ;***    The following four macros implement a call level stack
  2340. ;    for use by the CCall, PCall, and PushP macros.    They should
  2341. ;    not be invoked externally.
  2342.  
  2343. ?callsp = 0                ;; Call stack pointer is zero
  2344.  
  2345. ?stcallset macro    num,value
  2346.     ?stcall&num = value
  2347.     .xcref    ?stcall&num
  2348.     endm
  2349.  
  2350. ?stcallget macro    num,sym
  2351.     sym    = ?stcall&num
  2352.     endm
  2353.  
  2354. ?callpush macro value
  2355.     .lall
  2356.     ?callsp = ?callsp + 1
  2357.     .xall
  2358.     ?stcallset %?callsp,value
  2359.     endm
  2360.  
  2361. ?callpop macro    sym
  2362.     .errnz    (?callsp eq 0)
  2363.     ?stcallget %?callsp,sym
  2364.     .lall
  2365.     ?callsp = ?callsp - 1
  2366.     .xall
  2367.     endm
  2368.  
  2369.  
  2370. ;*** PCall - Call PASCAL "C" function
  2371. ;
  2372. ;    Call a near pascal procedure that may be external.  Uses pascal
  2373. ;    argument order (args are pushed left to right).  The callee must
  2374. ;    remove the arguments (with RET n).
  2375.  
  2376. PCall    macro    name, arglst, testarg
  2377.     if2
  2378.     ifnb <testarg>
  2379.         ProcError <Too many args in PCall name>
  2380.         .err
  2381.     endif
  2382.     if ?bmcpushp
  2383.         ProcError <PushP used before PCall name>
  2384.         .err
  2385.     endif
  2386.     endif
  2387.     ?argc = 0
  2388.     irp x,<arglst>
  2389.     push x
  2390.     ?argc = ?argc + 1
  2391.     endm
  2392.     ifdef ?&name
  2393.     if ?&name NE -1
  2394.         if ?argc NE ?&name
  2395.         if1
  2396.             ProcError <Wrong number of arguments in PCall name>
  2397.         endif
  2398.            .err
  2399.         endif
  2400.     endif
  2401.     endif
  2402.     call  name
  2403. endm
  2404.  
  2405.  
  2406. ;*** CCall - Call normal "C" function
  2407. ;
  2408. ;    Call a near "C" procedure that may be external.  Uses "C" argument
  2409. ;    order (args are pushed right to left).    The arguments are removed
  2410. ;    after the call if cdecl was indicated or -DSTDCALL not used.
  2411. ;    "name" is empty when the caller just wants to clear PushP nesting
  2412. ;
  2413. ;   USES
  2414. ;    Flags (only when arguments are removed from the stack by this macro).
  2415.  
  2416. ?CC_CDECL    equ    01h
  2417. ?CC_PASCAL    equ    02h
  2418. ?CC_PUSHP    equ    04h
  2419. ?CC_FAR32    equ    08h
  2420.  
  2421. CCall    macro    name, arglst, modifiers, testarg
  2422.     ?ccflags = 0        ;; assume new C calling convention, no PushP
  2423.     irp x,<modifiers>                ;; examine modifiers
  2424.     ifnb <x>
  2425.         ifidn <x>,<cdecl>
  2426.         ?ccflags = ?ccflags or ?CC_CDECL    ;; cdecl override
  2427.         elseifidn <x>,<pascal>
  2428.         ?ccflags = ?ccflags or ?CC_PASCAL    ;; pascal override
  2429.         elseifidn <x>,<PushP>
  2430.         ?ccflags = ?ccflags or ?CC_PUSHP    ;; PushP used
  2431.         elseifidn <x>,<far32>
  2432.         ?ccflags = ?ccflags or ?CC_FAR32    ;; far32 call
  2433.         elseif2
  2434.         ProcError <Bad PushP/cdecl/pascal arg in CCall name: x>
  2435.         .err
  2436.         endif
  2437.     endif
  2438.     endm
  2439.     ifndef STDCALL        ;; if using old C compiler calling convention
  2440.     if ((?ccflags and ?CC_PASCAL) eq 0)
  2441.         ?ccflags = ?ccflags or ?CC_CDECL    ;; force cdecl override
  2442.     endif
  2443.     endif
  2444.     if2
  2445.     ifnb <testarg>
  2446.         ProcError <Too many args in CCall name>
  2447.         .err
  2448.     endif
  2449.     if ((?ccflags and ?CC_PUSHP) eq 0) and (?bmcpushp ne 0)
  2450.         ProcError <PushP expected in CCall name> ;; if no PushP, but needed
  2451.         .err
  2452.     endif
  2453.     if ((?ccflags and (?CC_CDECL or ?CC_PASCAL)) eq \
  2454.               (?CC_CDECL or ?CC_PASCAL))
  2455.         ProcError <pascal and cdecl conflict in CCall name>
  2456.         .err
  2457.     endif
  2458.     endif
  2459.     .lall
  2460.     ?bm1 = ?ccflags                ;; only for listing files
  2461.     .xall
  2462.  
  2463.     ?argc = 0
  2464.     if (?ccflags and ?CC_PASCAL)        ;; if pascal used
  2465.     irp x,<arglst>                ;; push args left to right
  2466.         push x
  2467.         ?argc = ?argc + 1
  2468.     endm
  2469.     else                    ;; else C order
  2470.     ?Arg <arglst>                ;; push args right to left
  2471.     endif
  2472.     if (?ccflags and ?CC_PUSHP)         ;; if PushP used
  2473.     if2
  2474.         ife ?bmcpushp            ;; if PushP not needed
  2475.         ProcError <PushP unexpected in CCall name>
  2476.         .err
  2477.         endif
  2478.     endif
  2479.     ?argc = ?argc + ?bmcpushp        ;; remove the PushP parms, too
  2480.     endif
  2481.     if (?ccflags and ?CC_FAR32)
  2482.     CatPrefix <call far ptr FLAT:>, %F32PRE_, <name>
  2483.     else
  2484.     call  name                ;; call the target
  2485.     endif
  2486.                         ;; if cdecl && arg count != 0
  2487.     if ((?ccflags and ?CC_CDECL) ne 0) and (?argc ne 0)
  2488.     ?Eval add  esp,%(?argc*4)        ;; remove the parms
  2489.     endif
  2490.     ife ?callsp
  2491.     ?bmcpushp = 0
  2492.     else
  2493.     ?callpop ?bmcpushp
  2494.     endif
  2495. endm
  2496.  
  2497.  
  2498. ;*** PushP - push a dword parameter in advance of a CCall invocation
  2499. ;
  2500. ;    Push the parameter and increment the parameter count.
  2501.  
  2502. ?bmcpushp = 0
  2503.  
  2504. PushP    macro    value, testarg
  2505.     if2
  2506.     ifnb <testarg>
  2507.         ProcError <Too many args in PushP value>
  2508.         .err
  2509.     endif
  2510.     endif
  2511.     ?bmcpushp = ?bmcpushp + 1
  2512.     PUSHD  <value>
  2513. endm
  2514.  
  2515.  
  2516. ;***    CCallNest - begin nested CCall level
  2517. ;
  2518. ;    Push the current parameter count and reinitialize the
  2519. ;    counter to zero.
  2520.  
  2521. CCallNest macro
  2522.     ife ?bmcpushp or ?callsp
  2523.         ProcError <No parameters pushed before nesting>
  2524.         .err
  2525.         exitm
  2526.     endif
  2527.     ?callpush ?bmcpushp
  2528.     ?bmcpushp = 0
  2529.     endm
  2530.  
  2531.  
  2532. ;*** BugBug - Document incomplete code, temporary assumptions, etc
  2533. ;
  2534. ;   ENTRY
  2535. ;    d    - in the format DD-MMM-YY (eg, 06-Jan-88)
  2536. ;    id   - your email ID (eg, JeffPar)
  2537. ;    note - a few words about the problem, assumption, etc, in brackets (<>)
  2538. ;
  2539.  
  2540. BugBug    macro    d,id,note
  2541.     ?bm1 sizestr <d>
  2542.     if ?bm1 NE 9
  2543.       %out Bad date in BUGBUG
  2544.       .err
  2545.     endif
  2546.     if1
  2547.       ifndef NOBUGBUG
  2548.         %out BUGBUG d id:  note
  2549.       endif
  2550.     endif
  2551.     ifdef ERRBUGBUG
  2552.       .err
  2553.     endif
  2554. endm
  2555.  
  2556. ;*** movzxESP - movzx esp,sp with private stack check               ;whs
  2557. ;                                       ;whs
  2558. ;   ENTRY                                   ;whs
  2559. ;    none                                   ;whs
  2560. ;                                       ;whs
  2561. ;   USES                                   ;whs
  2562. ;    reg, Flags                               ;whs
  2563. ;                                       ;whs
  2564.                                        ;whs
  2565. movzxESP   macro                               ;whs
  2566. local    l1                                   ;whs
  2567.     push    ax                               ;whs
  2568.     mov    ax,ss                               ;whs
  2569.     cmp    ax,seg FLAT:DGROUP                       ;whs
  2570.     pop    ax                               ;whs
  2571.     je    short l1                           ;whs
  2572.     movzx    esp,sp                               ;whs
  2573.  l1:                                       ;whs
  2574.     endm                                   ;whs
  2575.                                        ;whs
  2576. ;*** SSToDS_PS - Convert SS-rel offset to DS-relative offset (private St ac;whs
  2577. ;                                       ;whs
  2578. ;   ENTRY                                   ;whs
  2579. ;    reg - register containing offset to be converted           ;whs
  2580. ;    val - optional memory location to take offset of (if not in reg  al;whs
  2581. ;                                       ;whs
  2582. ;   USES                                   ;whs
  2583. ;    reg, Flags                               ;whs
  2584. ;                                       ;whs
  2585.                                        ;whs
  2586. SSToDS_PS  macro   reg,val                           ;whs
  2587. local    l1                                   ;whs
  2588.     ifnb    <val>                               ;whs
  2589.       lea      reg,val                           ;whs
  2590.     endif                                   ;whs
  2591.       push      ax                               ;whs
  2592.       mov      ax,ss                            ;whs
  2593.       cmp      ax,seg FLAT:DGROUP                       ;whs
  2594.       pop      ax                               ;whs
  2595.       je      l1                               ;whs
  2596.       add      reg,[_TKSSBase]                       ;whs
  2597.      l1:                                   ;whs
  2598.     endm                                   ;whs
  2599.                                        ;whs
  2600. ;*** DSToSS_PS - Convert DS-relative offset to SS-relative offset (priva te;whs
  2601. ;                                       ;whs
  2602. ;   ENTRY                                   ;whs
  2603. ;    reg - register containing offset to be converted           ;whs
  2604. ;    val - optional memory location to take offset of (if not in reg  al;whs
  2605. ;                                       ;whs
  2606. ;   USES                                   ;whs
  2607. ;    reg, Flags                               ;whs
  2608.                                        ;whs
  2609. DSToSS_PS  macro   reg,val                           ;whs
  2610. local    l1                                   ;whs
  2611.     ifnb    <val>                               ;whs
  2612.       lea      reg,val                           ;whs
  2613.     endif                                   ;whs
  2614.       push      ax                               ;whs
  2615.       mov      ax,ss                            ;whs
  2616.       cmp      ax,seg FLAT:DGROUP                       ;whs
  2617.       pop      ax                               ;whs
  2618.       je      l1                               ;whs
  2619.       sub      reg,[_TKSSBase]                       ;whs
  2620.      l1:                                   ;whs
  2621.     endm                                   ;whs
  2622.                                        ;whs
  2623.  
  2624. ;*** SSToDS - Convert SS-relative offset to DS-relative offset
  2625. ;
  2626. ;   ENTRY
  2627. ;    reg - register containing offset to be converted
  2628. ;    val - optional memory location to take offset of (if not in reg already)
  2629. ;
  2630. ;   USES
  2631. ;    reg, Flags
  2632. ;
  2633.  
  2634. SSToDS    macro    reg,val
  2635.     ifnb    <val>
  2636.       lea      reg,val
  2637.     endif
  2638.       add      reg,[_TKSSBase]
  2639.     endm
  2640.  
  2641. ;*** DSToSS - Convert DS-relative offset to SS-relative offset
  2642. ;
  2643. ;   ENTRY
  2644. ;    reg - register containing offset to be converted
  2645. ;    val - optional memory location to take offset of (if not in reg already)
  2646. ;
  2647. ;   USES
  2648. ;    reg, Flags
  2649.  
  2650. DSToSS    macro    reg,val
  2651.     ifnb    <val>
  2652.       lea      reg,val
  2653.     endif
  2654.       sub      reg,[_TKSSBase]
  2655.     endm
  2656.  
  2657. ;*** PopAll - pop user's registers
  2658. ;
  2659.  
  2660. PopAll    macro
  2661.     .386p
  2662.     popad
  2663.     pop    gs
  2664.     pop    fs
  2665.     CPUMode reset
  2666.     pop    es
  2667.     pop    ds
  2668. endm
  2669.  
  2670. ;*** PushAll - push user's registers
  2671. ;
  2672.  
  2673. PushAll macro
  2674.     push    ds
  2675.     push    es
  2676.     .386p
  2677.     push    fs
  2678.     push    gs
  2679.     pushad
  2680.     CPUMode reset
  2681. endm
  2682.  
  2683. ;*** IODELAY - generate delay between I/O instructions
  2684. ;
  2685. ;   Use this between two adjacent I/O instructions.
  2686. ;
  2687. ;   EXIT    Code generated to cause a slight delay.
  2688.  
  2689. IODELAY macro
  2690.     jmp    short $+2
  2691. endm
  2692.  
  2693. ;*** RETD - Default 32-bit return
  2694. ;
  2695.  
  2696. RETD    macro    nparms
  2697.     ?RET <ne>, <ret>, <nparms>
  2698. endm
  2699.  
  2700. ;*** RETND - Near 32-bit return
  2701. ;
  2702.  
  2703. RETND    macro    nparms
  2704.     ?RET <ne>, <retn>, <nparms>
  2705. endm
  2706.  
  2707. ;*** RETFD - Far 32-bit return
  2708. ;
  2709.  
  2710. RETFD    macro    nparms
  2711.     ?RET <ne>, <retf>, <nparms>
  2712. endm
  2713.  
  2714. ;*** RETW - Default 16-bit return
  2715. ;
  2716.  
  2717. RETW    macro    nparms
  2718.     ?RET <eq>, <ret>, <nparms>
  2719. endm
  2720.  
  2721. ;*** RETNW - Near 16-bit return
  2722. ;
  2723.  
  2724. RETNW    macro    nparms
  2725.     ?RET <eq>, <retn>, <nparms>
  2726. endm
  2727.  
  2728. ;*** RETFW - Far 16-bit return
  2729. ;
  2730.  
  2731. RETFW    macro    nparms
  2732.     ?RET <eq>, <retf>, <nparms>
  2733. endm
  2734.  
  2735. ;*** ?RET - RET* worker macro
  2736. ;
  2737.  
  2738. ?RET    macro    rel, retinst, nparms
  2739.     if (?cstype rel ?CS_32bit)
  2740.     db    MI_OPERANDSIZE
  2741.     endif
  2742.     retinst nparms
  2743. endm
  2744.  
  2745. ;*** PUSHD - push dword value no matter the code segment type
  2746. ;
  2747. ;   Normally immediate and segment registers push a word or
  2748. ;   dword on the stack depending on the code segment type.  This
  2749. ;   macro always pushes the "value" as a dword (unless "value" is
  2750. ;   a 16 bit register).
  2751. ;
  2752. ;   ENTRY   value
  2753. ;
  2754. ;   EXIT    NONE
  2755. ;
  2756. ;   USES    NONE
  2757.  
  2758. PUSHD    macro    value, testarg
  2759.     if2
  2760.     .errnb <testarg>            ;; too many args
  2761.     irp x,<ax,bx,cx,dx,si,di,bp,sp>
  2762.         ifidni <x>,<value>
  2763.         ProcError <PUSHD: 16 bit register: x>
  2764.         .err
  2765.         endif
  2766.     endm
  2767.     endif
  2768.     ?bm1 = .type value                ;; helps debug the macro
  2769.     ?bm1 = 2                    ;; use simple push
  2770.     if (?cstype ne ?CS_32bit)
  2771.     ?bm1 = 0                ;; use dword ptr push
  2772.     irp x,<cs,ds,es,fs,gs,ss>
  2773.         ifidni <x>,<value>
  2774.         ?bm1 = 1            ;; use explicit override
  2775.         endif
  2776.     endm
  2777.     if (?bm1 eq 0)
  2778.         if (((.type (value)) and 07h) eq 04h) ;; if simple constant
  2779.         if ((value) lt 128) and ((value) gt -129)
  2780.             ?bm1 = 1            ;; use explicit override
  2781.         endif
  2782.         elseif ((.type (value)) and 10h)    ;; if register
  2783.         ?bm1 = 2            ;; use simple push
  2784.         endif
  2785.     endif
  2786.     endif
  2787.     if (?bm1 eq 0)
  2788.     push    dword ptr (value)
  2789.     else
  2790.     if (?bm1 eq 1)                ;; explicit override
  2791.         db    MI_OPERANDSIZE
  2792.     endif
  2793.     push    value
  2794.     endif
  2795. endm
  2796.  
  2797. ;*** POPD - pop dword value no matter the code segment type
  2798. ;
  2799. ;   Normally segment registers pop a word or dword on the stack
  2800. ;   depending on the code segment type.  This macro always popes
  2801. ;   the "value" as a dword (unless "value" is a 16 bit register).
  2802. ;
  2803. ;   ENTRY   value
  2804. ;
  2805. ;   EXIT    NONE
  2806. ;
  2807. ;   USES    NONE
  2808.  
  2809. POPD    macro    value, testarg
  2810.     if2
  2811.     .errnb <testarg>            ;; too many args
  2812.     irp x,<ax,bx,cx,dx,si,di,bp,sp>
  2813.         ifidni <x>,<value>
  2814.         ProcError <POPD: 16 bit register: x>
  2815.         .err
  2816.         endif
  2817.     endm
  2818.     endif
  2819.     ?bm1 = .type value                ;; helps debug the macro
  2820.     ?bm1 = FALSE
  2821.     if (?cstype eq ?CS_32bit)
  2822.     pop    value
  2823.     else
  2824.     irp x,<cs,ds,es,fs,gs,ss>
  2825.         ifidni <x>,<value>
  2826.         db    MI_OPERANDSIZE
  2827.         pop    value
  2828.         ?bm1 = TRUE
  2829.         endif
  2830.     endm
  2831.     if ?bm1 eq FALSE
  2832.         if ((.type value) and 10h)    ;; if register
  2833.         pop    value
  2834.         else
  2835.         pop    dword ptr value
  2836.         endif
  2837.     endif
  2838.     endif
  2839. endm
  2840.  
  2841. ;   This section contains macros to get around the 386 chip bug
  2842. ;   regarding use of LSL, LAR, VERR, and VERW instructions.
  2843. ;
  2844. ;   If a bad selector is passed to any instruction above, it may
  2845. ;   cause the 386 processor to hang up after executing the
  2846. ;   instruction.  A workaround for this is to follow the instructions
  2847. ;   with a jmp, and have the last byte of instructions aligned in the
  2848. ;   same dword as all of jmp instruction; so that both instructions will
  2849. ;   be prefetched together.
  2850. ;
  2851. ;   BUGBUG:  The code segments used must be DWORD aligned in order for
  2852. ;   these macros to work properly.  There is an ALIGN 4 directive in
  2853. ;   the ?Bug386 macro that should help insure this (however, the assembler
  2854. ;   only seems to complain if the align-type is BYTE;  WORD works, but
  2855. ;   musn't be allowed).
  2856. ;
  2857.  
  2858. ;*** LOADSL - Macro to replace 'lsl reg,sel'
  2859. ;
  2860.  
  2861. LOADSL    macro    reg,sel
  2862.     .errb <reg>
  2863.     .errb <sel>
  2864.     ?Bug386 lsl,<reg>,sel
  2865. endm
  2866.  
  2867. ;*** LOADAR - Macro to replace 'lar reg,sel'
  2868. ;
  2869.  
  2870. LOADAR    macro    reg,sel
  2871.     .errb <reg>
  2872.     .errb <sel>
  2873.     ?Bug386 lar,<reg>,sel
  2874. endm
  2875.  
  2876. ;*** VERIFYREAD - Macro to replace 'verr sel'
  2877. ;
  2878. ;   The second variable is a scratch register which improves
  2879. ;   performance if provided and sel is not a register variable.
  2880. ;
  2881.  
  2882. VERIFYREAD macro    sel,screg
  2883.     .errb <sel>
  2884.     ?Bug386 verr,,<sel>,screg
  2885. endm
  2886.  
  2887. ;*** VERIFYWRITE - Macro to replace 'verw sel'
  2888. ;
  2889. ;   The second variable is a scratch register which improves
  2890. ;   performance if provided and sel is not a register variable.
  2891. ;
  2892.  
  2893. VERIFYWRITE macro   sel,screg
  2894.     .errb <sel>
  2895.     ?Bug386 verw,,<sel>,screg
  2896. endm
  2897.  
  2898. ;*** ?Bug386
  2899. ;
  2900. ;   This macro provides a workaround the 386 chip bug
  2901. ;   that causes the processor to hang if a bad selector
  2902. ;   is passsed to any of the instructions lsl, lar, verr,
  2903. ;   and verw. It puts the last byte of the given instruction
  2904. ;   in the same dword with the following jnz instruction
  2905. ;
  2906.  
  2907. ?Bug386 macro    inst,reg,sel,screg
  2908.     local zero
  2909.     ?bm1 = TRUE
  2910.     irp x,<ax,bx,cx,dx,si,di>
  2911.     ifidni <sel>,<x>        ;; Is sel a register?
  2912.         ?bm1 = FALSE
  2913.         exitm
  2914.     endif
  2915.     endm
  2916.     ifnb <reg>                ;; if it is lsl or lar
  2917.     irp x,<eax,ebx,ecx,edx,esi,edi>
  2918.         ifidni <sel>,<x>        ;; 32 bit registers are also OK
  2919.         ?bm1 = FALSE
  2920.         exitm
  2921.         endif
  2922.     endm
  2923.     endif
  2924.     if ?bm1                ;; Set up sel in a register
  2925.     ifb <reg>            ;; if it is verr or verw
  2926.         ifb <screg>         ;; if no scratch register
  2927.         push  ax        ;; save ax
  2928.         mov   ax,sel        ;; (ax) = sel
  2929.         else            ;; else use scratch register
  2930.         mov   screg,sel
  2931.         endif
  2932.     else                ;; if it is lsl or lar
  2933.         mov  reg,sel
  2934.     endif
  2935.     endif
  2936.  
  2937.     ?i = $
  2938.     org 0
  2939.     zero label near
  2940.     align 4                ;; the "align" is superfluous at
  2941.                     ;; offset 0;  idea is to try to insure
  2942.                     ;; proper segment align-type (DWORD)
  2943.     org ?i
  2944.     ?i = ($ - offset cs:zero) mod 4    ;; calculate how many
  2945.     ?i = (6 - ?i) mod 4         ;; NOPS needed for padding
  2946.     rept ?i
  2947.     nop
  2948.     endm
  2949.     ?i = $                ;; this label must be odd-word aligned
  2950.     if ?bm1
  2951.     ifb <reg>            ;; If it is verr or verw
  2952.         ifb <screg>         ;; No scratch register
  2953.         inst  ax
  2954.         else            ;; use scratch register
  2955.         inst  screg
  2956.         endif
  2957.     else
  2958.         inst  reg,reg        ;; lsl or lar
  2959.     endif
  2960.     else
  2961.     ifb <reg>
  2962.         inst  sel
  2963.     else
  2964.         inst  reg,sel
  2965.     endif
  2966.     endif
  2967.     jmp short $+2            ;; Must be in the same dword with the
  2968.                     ;; last byte of previous instruction
  2969.     if ($ - ?i - 5)
  2970.     if ($ - ?i - 6)
  2971.         .err            ;; Len must be 5 bytes (6 if 32bit reg)
  2972.     endif
  2973.     endif
  2974.     if ?bm1                  ;; Did we push ax?
  2975.     ifb <reg>
  2976.         ifb <screg>
  2977.         pop  ax
  2978.         endif
  2979.     endif
  2980.     endif
  2981. endm
  2982.  
  2983. ;***    B1EMac - 386 B1 Errata Macro
  2984. ;
  2985. ;    This macro generates workarounds for the erratum 7 on the 386 B1
  2986. ;    errata sheet dated September 1 1987:
  2987. ;
  2988. ;    <Begin Quote:>
  2989. ;    Wrong Register Size for String Instructions in Mixed 16/32-bit
  2990. ;    Addressing Systems.
  2991. ;
  2992. ;    Problem:  If certain string and loop instructions are followed by
  2993. ;    instructions that either:
  2994. ;
  2995. ;    1)  use a different address size (that is, if either the string
  2996. ;        instruction or the following instruction uses an address size
  2997. ;        prefix), or
  2998. ;
  2999. ;    2)  reference the stack (e.g. PUSH/POP/CALL/RET) and the "B" bit
  3000. ;        in the SS descriptor is different from the address size used
  3001. ;        by the string instructions,
  3002. ;
  3003. ;    then one or more of (E)CX, (E)SI, or (E)DI is not updated properly.
  3004. ;    The size of the register (16 vs. 32) is taken from the following
  3005. ;    instruction rather than the from the string or loop instruction.
  3006. ;    This could result in updating only the lower 16 bits of a 32 bit
  3007. ;    register, or in updating all 32 bits of a register being used as
  3008. ;    16 bits.  The instructions and registers affected by this are listed
  3009. ;    below:
  3010. ;
  3011. ;        Instruction    Register(s)
  3012. ;            MOVS      (E)DI
  3013. ;            REP MOVS      (E)SI
  3014. ;            STOS      (E)DI
  3015. ;            INS       (E)DI
  3016. ;            REP INS      (E)CX
  3017. ;
  3018. ;    Workaround: No workaround is necessary if all code is 16-bit or if
  3019. ;    all code is 32-bit.  The problem only occurs if instructions with
  3020. ;    different address sizes are mixed together, or if a code segment of
  3021. ;    one size used with a stack segment of the other size.
  3022. ;
  3023. ;    In a system which mixes address sizes, add a NOP after each of the
  3024. ;    above instrcutions and ensure that the NOP has the same address
  3025. ;    size as the string/loop (i.e., if the string/loop instruction
  3026. ;    includes as address prefix, place the same address prefix before
  3027. ;    the NOP; conversely, if the string/loop instruction does not have
  3028. ;    an address prefix, do not place a prefix before the NOP).
  3029. ;    <End Quote>
  3030. ;
  3031. ;    Invocation examples:
  3032. ;        B1EMac   insb
  3033. ;        B1EMac   repne ins dword ptr es:[di],dx
  3034. ;        B1EMac   rep movsw
  3035. ;        B1EMac   movs byte ptr es:[edi],byte ptr gs:[esi]
  3036. ;        B1EMac   stos dword ptr es:[di]
  3037. ;    No white space is allowed on either size of the colons or on either
  3038. ;    side of the registers within square brackets ("es:[edi]" must be one
  3039. ;    token).
  3040. ;
  3041. ;    ENTRY    reparg    = <blank>,rep,repne,etc.    (optional)
  3042. ;        instr    = ins*,movs*,stos*
  3043. ;        dstsize = <blank>,byte,word,dword
  3044. ;        dstptr    = <blank>,ptr
  3045. ;        dstreg    = <blank>,es:[di],es:[edi]
  3046. ;        srcsize = <blank>,byte,word,dword
  3047. ;        srcptr    = <blank>,ptr
  3048. ;        srcreg    = <blank>,?s:[si],?s:[esi]
  3049. ;        testarg = <blank>
  3050. ;    (global variables)
  3051. ;        ?cstype = ?CS_32bit or 0 to indicate default address size
  3052. ;
  3053. ;    EXIT    code generated to invoke the instruction with workaround
  3054.  
  3055. ?BE_REP   equ 0001h    ; valid rep prefix
  3056. ?BE_LONG  equ 0002h    ; long form of instruction
  3057. ?BE_SHORT  equ 0004h    ; short form of instruction
  3058.  
  3059. B1EMac    macro  reparg,instr,dstsize,dstptr,dstreg,srcsize,srcptr,srcreg,testarg
  3060.     if2
  3061.     .errnb <testarg>            ;; too many args
  3062.     endif
  3063.     ?bm1 = 0
  3064.     ?bm2 = ?cstype                ;; assume default address size
  3065.     ifnb <reparg>
  3066.     irp reptmp,<rep,repe,repz,repne,repnz>    ;; valid rep prefix?
  3067.         ifidni <reparg>,<reptmp>
  3068.         ?bm1 = ?bm1 or ?BE_REP        ;; Yes.
  3069.         endif
  3070.     endm
  3071.     if ((?bm1 and ?BE_REP) eq 0)        ;; else reinvoke with blank rep
  3072.         B1EMac <> reparg instr dstsize dstptr dstreg, srcsize srcptr srcreg
  3073.         exitm                ;; and terminate the macro
  3074.     endif
  3075.     endif
  3076.     irp insttmp,<movs,ins,stos>         ;; long form of instruction?
  3077.     ifidni <instr>,<insttmp>
  3078.         ?bm1 = ?bm1 or ?BE_LONG        ;; Yes.
  3079.     endif
  3080.     endm
  3081.     if (?bm1 and ?BE_LONG)            ;; long form?
  3082.     ifidni <dstreg>,<es:[edi]>
  3083.         ?bm2 = ?CS_32bit            ;; 32-bit address size
  3084.     elseifidni <dstreg>,<es:[di]>
  3085.         ?bm2 = 0                ;; 16-bit address size
  3086.     elseif2
  3087.         ifb <dstreg>
  3088.         %out B1EMac: destination register required
  3089.         else
  3090.         %out B1EMac: bad destination register: dstreg
  3091.         endif
  3092.         .err
  3093.     endif
  3094.     else                    ;; else valid short form?
  3095.     irp insttmp,<movsb,movsw,movsd,insb,insw,insd,stosb,stosw,stosd>
  3096.         ifidni <instr>,<insttmp>
  3097.         ?bm1 = ?bm1 or ?BE_SHORT    ;; Yes.
  3098.         endif
  3099.     endm
  3100.     if ((?bm1 and ?BE_SHORT) eq 0)
  3101.         if2
  3102.         %out B1EMac: bad instruction: instr
  3103.         .err
  3104.         endif
  3105.     endif
  3106.     endif
  3107.     ifnb <srcsize>                ;; comma required?
  3108.     reparg instr dstsize dstptr dstreg, srcsize srcptr srcreg
  3109.     else
  3110.     reparg instr dstsize dstptr dstreg
  3111.     endif
  3112.     if (?bm2 ne (?cstype and ?CS_32bit))    ;; add override if needed
  3113.     db    MI_ADDRESSSIZE
  3114.     endif
  3115.     nop
  3116. endm
  3117.  
  3118. ;***    btrx, btsx, orb, andb, testb, etc.
  3119. ;
  3120. ;    These macros allow you to generate more space-efficient 386 code,
  3121. ;    by oring/anding/testing only individual bytes of dwords, provided the
  3122. ;    mask (source operand) contains bits in exactly one byte; eg,
  3123. ;
  3124. ;        test    [foo],00000000000000001111111100000000b
  3125. ;
  3126. ;    can be written as
  3127. ;
  3128. ;        testb   [foo],00000000000000001111111100000000b
  3129. ;
  3130. ;    which will automatically generate the following:
  3131. ;
  3132. ;        test    byte ptr [foo+1],11111111b
  3133. ;
  3134. ;    The btrx and and btsx macros simply let you feed a normal bitmask
  3135. ;    into a btr or bts instruction, instead of a bit offset (which we
  3136. ;    generally don't have equates for).
  3137. ;
  3138.  
  3139. orb    macro    dst,src
  3140.     ?ins    or,dst,src,0
  3141.     endm
  3142.  
  3143. andb    macro    dst,src
  3144.     ?ins    and,dst,src,0ffh
  3145.     endm
  3146.  
  3147. clrb    macro    dst,src
  3148.     ?ins    and,dst,%(not src),0ffh
  3149.     endm
  3150.  
  3151. xorb    macro    dst,src
  3152.     ?ins    xor,dst,src,0
  3153.     endm
  3154.  
  3155. testb    macro    dst,src
  3156.     ?ins    test,dst,src,0
  3157.     endm
  3158.  
  3159. ?ins    macro    ins,dst,src,b
  3160.     ?bm1 = 0
  3161.     ?bm2 = 0
  3162.     ?bm3 = 0ffh
  3163.     ?bm4 = b
  3164.     rept 4
  3165.       if (src and ?bm3) ne ?bm4
  3166.         ?bm5 = ?bm1
  3167.         ?bm2 = ?bm2 + 1
  3168.       endif
  3169.       ?bm1 = ?bm1 + 1
  3170.       ?bm3 = ?bm3 shl 8
  3171.       ?bm4 = ?bm4 shl 8
  3172.     endm
  3173.     if (?bm2 ne 1)
  3174.     ins    dst,src
  3175.     else
  3176.     ?insx    ins,dst,src,%?bm5
  3177.     endif
  3178.     endm
  3179.  
  3180. ?insx    macro    ins,dst,src,i
  3181.     ins    byte ptr dst+i,src shr (i*8)
  3182.     endm
  3183.  
  3184. btx    macro    dst,src
  3185.     ?bitno    src
  3186.     bt    dst,?bm1
  3187.     endm
  3188.  
  3189. btcx    macro    dst,src
  3190.     ?bitno    src
  3191.     btc    dst,?bm1
  3192.     endm
  3193.  
  3194. btrx    macro    dst,src
  3195.     ?bitno    src
  3196.     btr    dst,?bm1
  3197.     endm
  3198.  
  3199. btsx    macro    dst,src
  3200.     ?bitno    src
  3201.     bts    dst,?bm1
  3202.     endm
  3203.  
  3204. ?bitno    macro    m
  3205.     ?bm1 = 0
  3206.     ?bm2 = m
  3207.     rept 32
  3208.       ?bm2 = ?bm2 shr 1
  3209.       if ?bm2 ne 0
  3210.         ?bm1 = ?bm1 + 1
  3211.       endif
  3212.     endm
  3213.     endm
  3214.  
  3215.  
  3216. ;***    GenHybrid - generate a far entry header for a faronly procedure
  3217. ;***    ?Gen16 - generate a far entry header for a far16 procedure
  3218. ;***    GenFar32 - generate a far entry header for a far32 procedure
  3219. ;
  3220. ;    A faronly/far16/far32 procedure is constructed by creating a
  3221. ;    faronly/far16/far32 entry header followed by a near procedure.
  3222. ;
  3223. ;   ENTRY   name = name of procedure
  3224. ;        lcl  = blank - make the far entry point public
  3225. ;         = non-blank - if symbol NOLOCAL is defined, then
  3226. ;                   the entry is made public anyway.
  3227. ;                   Else it is made 'local' by renaming
  3228. ;                   it into lxx_&name (xx is a unique
  3229. ;                   number) and declared public. This is
  3230. ;                   useful for symbolic debugging.
  3231. ;        usecall = blank - assume that this thunk immediately
  3232. ;                  precedes the real function, and that
  3233. ;                  control can fall through
  3234. ;            = non-blank - assume that another thunk will be
  3235. ;                  between this one and the real function,
  3236. ;                  so we must use a CALL to invoke it.  Note
  3237. ;                  that this precludes the use of ArgVar.
  3238. ;        (global vars)
  3239. ;        NOLOCAL = undefined - let lcl controls whether the
  3240. ;                      entry point should be (fake)
  3241. ;                      local or public.
  3242. ;            = defined - make entry point public no matter
  3243. ;                    what "lcl" is.
  3244. ;
  3245. ;   EXIT    A far entry header (code and pseudo ops) generated.
  3246. ;        A "public" pseudo op is generated to declare the
  3247. ;        entry point public or local (fake local).
  3248.  
  3249. GenHybrid macro name, lcl, usecall, half
  3250.     ?GenThunk <RETFOFFSET>, <RETFOFFSET>, <retf>, %HYBPRE_, <name>, <lcl>, <usecall>, <half>
  3251. endm
  3252.  
  3253. ?Gen16 macro name, lcl, usecall
  3254.     ?GenThunk <RETFDOFFSET>, <RETFDOFFSET>, <RETFD>, %F16PRE_, <name>, <lcl>, <usecall>
  3255. endm
  3256.  
  3257. GenFar32 macro name, lcl, usecall, half
  3258.     if2
  3259.     ifndef RETFDLabel
  3260.         extrn RETFDLabel:near
  3261.     endif
  3262.     endif
  3263.     ?GenThunk <RETFDOFFSET>, <offset FLAT:RETFDLabel>, <retf>, %F32PRE_, <name>, <lcl>, <usecall>, <half>
  3264. endm
  3265.  
  3266. ?GenThunk macro fretdef, retoffset, retinst, prefix, name, lcl, usecall, half
  3267.     local a
  3268.     ?bm1 = 3
  3269.     ifnb <half>
  3270.     ?bm1 = 0
  3271.     irp x,<half>
  3272.         ifidn <x>,<tolabel>
  3273.         ?bm1 = ?bm1 or 1
  3274.         elseifidn <x>,<afterlabel>
  3275.         ?bm1 = ?bm1 or 2
  3276.         elseif2
  3277.         %out bad half_arg to ?GenThunk: half
  3278.         .err
  3279.         endif
  3280.     endm
  3281.     endif
  3282.     if (?bm1 and 1)
  3283.     ifndef fretdef
  3284.         a:    retinst
  3285.     endif
  3286.     GenPublic prefix&name,<lcl>,<code> ;; generate a public or local symbol
  3287.     prefix&name label far
  3288.     endif
  3289.     if (?bm1 and 2)
  3290.     ifb <usecall>
  3291.         ifdef fretdef
  3292.         push  retoffset     ;; near-code must immediately follow
  3293.         else
  3294.         push  offset cs:a    ;; near-code must immediately follow
  3295.         endif
  3296.     else
  3297.         call    name
  3298.         retinst
  3299.     endif
  3300.     endif
  3301. endm
  3302.  
  3303. ifdef INCL_DEF
  3304.  
  3305. ;*** ?Alloc - Allocate well-aligned data
  3306. ;
  3307.  
  3308. ?Alloc    macro var,dtyp,val,f
  3309.       ifndef NOALIGN
  3310.         if ?cstype EQ ?CS_16bit
  3311.           ifidni <dtyp>,<dw>
  3312.         ?Align var,2
  3313.           elseif f
  3314.         ?Align var,2        ;; align structures as well
  3315.           endif
  3316.         elseif ?cstype EQ ?CS_32bit
  3317.           ifidni <dtyp>,<dd>
  3318.         ?Align var,4
  3319.           elseif f
  3320.         ?Align var,4        ;; align structures as well
  3321.           endif
  3322.         endif
  3323.       endif
  3324.       var dtyp val
  3325. endm
  3326.  
  3327. ;*** ?Align - Insure alignment is as specified
  3328. ;
  3329.  
  3330. ?Align    macro var,b
  3331.       ?bm1 = offset $
  3332.       ALIGN b
  3333.       if ?bm1 NE offset $
  3334.         ifnb <var>
  3335.           if1
  3336.         %out b-byte alignment adjustment:  var
  3337.           endif
  3338.         endif
  3339.       endif
  3340. endm
  3341.  
  3342. ;*** REALEVEN - This macro replaces EVEN when we have offsets
  3343. ;        above 32k in a segment. It is used in pdata.asm
  3344. ;        and is required because the current version of
  3345. ;        masm (5.10A.06) has a bug which makes it put
  3346. ;        3 bytes of padding rather than 1.
  3347. ;        If we change to a version of the assembler
  3348. ;        without this bug, we can remove this macro.
  3349.  
  3350. REALEVEN macro
  3351.  
  3352.     ?intgr = ($- TASKAREA:BASEPTDA) mod 2
  3353.  
  3354.     REPT    ?intgr
  3355.         db    0
  3356.     ENDM
  3357.  
  3358. endm
  3359.  
  3360. ;*** ?SetType - Set ?cstype to value specified
  3361. ;
  3362.  
  3363. ?SetType macro val
  3364.        ifdif <val>,<USE32>
  3365.          ?cstype = ?CS_16bit
  3366.        else
  3367.          ?cstype = ?CS_32bit
  3368.        endif
  3369. endm
  3370.  
  3371. ;*** ?PushSeg - Save segment state
  3372. ;
  3373.  
  3374. ?PushSeg macro n
  3375.     ifdif <n>,<0>
  3376.       ?segname&n catstr ?segname
  3377.       ?curseg&n catstr ?curseg
  3378.       ?cstype&n = ?cstype
  3379.       ?model&n = ?model
  3380.       ?declare&n = ?declare
  3381.     endif
  3382. endm
  3383.  
  3384. ;*** ?PopSeg - Restore segment state
  3385. ;
  3386.  
  3387. ?PopSeg macro n
  3388.     ifdif <n>,<0>
  3389.       ?segname catstr ?segname&n
  3390.       ?curseg catstr ?curseg&n
  3391.       ?cstype = ?cstype&n
  3392.       ?model = ?model&n
  3393.       ?declare = ?declare&n
  3394.     else
  3395.       ?segname equ <>
  3396.       ?curseg equ <>
  3397.       ?cstype = NULL
  3398.       ?model = NULL
  3399.       ?declare = NULL
  3400.     endif
  3401. endm
  3402.  
  3403. ;*** ?OpenSeg - Parse parameters to DefCode/DefData
  3404. ;
  3405.  
  3406. ?OpenSeg macro scope,class,model,type
  3407.       ?declare = NULL
  3408.       ifidni <scope>,<EXPORT>
  3409.         ?declare = ?PUBLIC
  3410.       elseifidni <scope>,<IMPORT>
  3411.         ?declare = ?EXTRN
  3412.       elseifdifi <scope>,<LOCAL>
  3413.        ifdef DEBUG
  3414.         if DEBUG eq 1
  3415.           ?declare = ?PUBLIC
  3416.         endif
  3417.        endif
  3418.       endif
  3419.       ifidni <model>,<C>
  3420.         ?model = ?C
  3421.       elseifidni <model>,<PASCAL>
  3422.         ?model = ?PASCAL
  3423.       else
  3424.         ?model = NULL
  3425.       endif
  3426.       ?nsegs = ?nsegs + 1
  3427.       % ifidni <?curseg>,<?segname>
  3428.         ?segname equ <>
  3429.       else
  3430.         ?Eval %?segname,segment
  3431.         ?curseg catstr ?segname
  3432.       endif
  3433. endm
  3434.  
  3435. ;*** ?CloseSeg - Parse parameters to EndCode/EndData
  3436. ;
  3437.  
  3438. ?CloseSeg macro scope,class,model,type,m
  3439.       % ifnb <?segname>
  3440.         ?Eval %?segname,ends
  3441.       endif
  3442.       if ?nsegs EQ 0
  3443.         if1
  3444.           %out Missing m directive
  3445.         endif
  3446.       else
  3447.         ?nsegs = ?nsegs - 1
  3448.       endif
  3449. endm
  3450.  
  3451. ;*** ?ToUpper - Converts string to upper-case, returned in ?upper
  3452. ;
  3453.  
  3454. ?ToUpper macro s
  3455.       ?upper equ <>
  3456.       irpc x,<s>
  3457.         if '&x' GE 'a'
  3458.           if '&x' LE 'z'
  3459.         ?t1 substr <ABCDEFGHIJKLMNOPQRSTUVWXYZ>,'&x'-'a'+1,1
  3460.         ?upper catstr ?upper,?t1
  3461.           else
  3462.         ?upper catstr ?upper,<&x>
  3463.           endif
  3464.         else
  3465.           ?upper catstr ?upper,<&x>
  3466.         endif
  3467.       endm
  3468.     endm
  3469.  
  3470. endif ; INCL_DEF
  3471.  
  3472. ;*** ?DefLabel - define a label using text-macro arguments
  3473. ;
  3474.  
  3475. ?DefLabel macro var,type
  3476.       .lall
  3477.       var label type
  3478.       .xall
  3479.     endm
  3480.  
  3481. ;*** ?DefExtrn - define an external using text-macro arguments
  3482. ;
  3483.  
  3484. ?DefExtrn macro var,type
  3485.       .lall
  3486.       extrn var:type
  3487.       .xall
  3488.     endm
  3489.  
  3490. ;*** ?DefPublic - define a public using text-macro arguments
  3491. ;
  3492.  
  3493. ?DefPublic macro var
  3494.       .lall
  3495.       public var
  3496.       .xall
  3497.     endm
  3498.  
  3499. ;*** ?DefField - define a field, and make it public if DEBUG defined true
  3500. ;
  3501.  
  3502. ?DefField macro fn,var,stmt
  3503.         ?F&fn macro
  3504.         var stmt
  3505.         endm
  3506.         ifdef DEBUG
  3507.           if DEBUG eq 1
  3508.         ifnb <var>
  3509.           ?D&fn macro
  3510.           public _&var
  3511.           _&var = var
  3512.           endm
  3513.         endif
  3514.           endif
  3515.         endif
  3516.       endm
  3517.  
  3518. ;*** ?Eval - Evaluates text-macros for readability in listings
  3519. ;
  3520.  
  3521. ?Eval    macro ins,a1,a2,a3,a4
  3522.       ifb <a3>
  3523.     ifb <a2>
  3524.       ins    a1
  3525.     else
  3526.       ins    a1,a2
  3527.     endif
  3528.       else
  3529.       ins    a1,[a2&a3&a4]
  3530.       endif
  3531. endm
  3532.  
  3533. ;*** ?BPEqu - Creates an equate for referencing vars via BP/EBP/ESP
  3534. ;
  3535.  
  3536. ?BPEqu    macro sym,typ,bpr,s,a
  3537.     ifb <typ>
  3538.       ifdifi <bpr>,<esp>
  3539.         .lall
  3540.         sym equ <[bpr&s&a]>
  3541.         .xall
  3542.       else
  3543.         .lall
  3544.         sym equ <[bpr&s&a+?stackdepth]>
  3545.         .xall
  3546.       endif
  3547.     else
  3548.       ifdifi <bpr>,<esp>
  3549.         .lall
  3550.         sym equ <(typ ptr [bpr&s&a])>
  3551.         .xall
  3552.       else
  3553.         .lall
  3554.         sym equ <(typ ptr [bpr&s&a+?stackdepth])>
  3555.         .xall
  3556.       endif
  3557.     endif
  3558.     endm
  3559.  
  3560. ;*** ?Arg - Processes argument list - used by CCall only
  3561. ;
  3562.  
  3563. ?Arg    macro    arglst
  3564.       irp x,<arglst>
  3565.         ?argc = ?argc + 1
  3566.         ?MArg push,<x>,%?argc
  3567.       endm
  3568.       ?bm1 = ?argc
  3569.       rept ?bm1
  3570.         ?InvPrg <?AM>,%?bm1
  3571.         ?bm1 = ?bm1 - 1
  3572.       endm
  3573.     endm
  3574.  
  3575. ;*** ?MArg - Makes a macro to do the specified operation
  3576. ;
  3577.  
  3578. ?MArg    macro    op,arg,num
  3579.       ?AM&num ¯o
  3580.       op  arg
  3581.       &endm
  3582.     endm
  3583.  
  3584. ;*** ?InvPrg - Concatenates, invokes and purges a macro
  3585. ;
  3586.  
  3587. ?InvPrg macro    name1,name2
  3588.       name1&name2
  3589.       purge name1&name2
  3590.     endm
  3591.  
  3592. ;*** ?Purge - Concatenates and purges a macro
  3593. ;
  3594.  
  3595. ?Purge    macro    name1,name2
  3596.       purge name1&name2
  3597.     endm
  3598.