home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / tolkit45.zip / os2tk45 / inc / basemaca.inc < prev    next >
Text File  |  1999-03-15  |  91KB  |  3,728 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. ifndef F190546
  2565. ;
  2566. ; F190546 is defined during build of c.baseos os2krnl (d189811)
  2567. ;
  2568. movzxESP   macro
  2569. local    l1
  2570.     ifndef _PSDStackSel
  2571.        _DATA segment
  2572.           extrn _PSDStackSel:dword
  2573.        _DATA ends
  2574.     endif
  2575.     push    ax
  2576.     push    ds
  2577.     mov    ax,seg FLAT:DGROUP
  2578.     mov    ds,ax
  2579.      ASSUME DS:FLAT
  2580.     mov    ax,ss
  2581.     cmp    ax,seg FLAT:DGROUP
  2582.     je    short l1
  2583.     cmp    ax,word ptr [_PSDStackSel]
  2584.     je    short l1
  2585.     movzx    esp,sp
  2586.  l1:
  2587.     pop    ds
  2588.      ASSUME DS:NOTHING
  2589.     pop    ax
  2590.     endm                                   ;whs
  2591. else
  2592. movzxESP   macro
  2593. local    l1
  2594.     ifndef GDT_PSD
  2595.        ReferGDT       GDT_PSD,WORD
  2596.     endif
  2597.     ifndef GDT_PTDA32
  2598.        ReferGDT       GDT_PTDA32,WORD
  2599.     endif
  2600.     ifndef GDT_INTSTACK32
  2601.        ReferGDT       GDT_INTSTACK32,WORD
  2602.     endif
  2603.  
  2604.     push    ax
  2605.     mov    ax,ss
  2606.     cmp    ax,seg FLAT:DGROUP
  2607.     je    short l1
  2608.     cmp    ax, GSEL GDT_PSD
  2609.     je    short l1
  2610.     cmp    ax, GSEL GDT_PTDA32
  2611.     je    short l1
  2612.     cmp    ax, GSEL GDT_INTSTACK32
  2613.     je    short l1
  2614.     and    esp, 0000ffffh
  2615.  l1:
  2616.     pop    ax
  2617.     endm                                   ;whs
  2618. endif
  2619.                                        ;whs
  2620. ;*** SSToDS_PS - Convert SS-rel offset to DS-relative offset (private St ac;whs
  2621. ;                                       ;whs
  2622. ;   ENTRY                                   ;whs
  2623. ;    reg - register containing offset to be converted           ;whs
  2624. ;    val - optional memory location to take offset of (if not in reg     al;whs
  2625. ;                                       ;whs
  2626. ;   USES                                   ;whs
  2627. ;    reg, Flags                               ;whs
  2628. ;                                       ;whs
  2629.  
  2630. ifndef SMP
  2631. SSToDS_PS  macro   reg,val                           ;whs
  2632. local    l1                                   ;whs
  2633.     ifnb    <val>                               ;whs
  2634.       lea      reg,val                           ;whs
  2635.     endif                                   ;whs
  2636.       push      ax                               ;whs
  2637.       mov      ax,ss                               ;whs
  2638.       cmp      ax,seg FLAT:DGROUP                       ;whs
  2639.       pop      ax                               ;whs
  2640.       je      l1                               ;whs
  2641.       add      reg,[_TKSSBase]                       ;whs
  2642.      l1:                                   ;whs
  2643.     endm                                   ;whs
  2644. else
  2645. SSToDS_PS  macro   reg,val                           ;whs
  2646. local    l0,l1
  2647.     ifnb    <val>                               ;whs
  2648.       lea      reg,val                           ;whs
  2649.     endif                                   ;whs
  2650.       push      ax                               ;whs
  2651.       mov      ax,ss                               ;whs
  2652.       cmp      ax,seg FLAT:DGROUP                       ;whs
  2653.       pop      ax                               ;whs
  2654.       je      l1                               ;whs
  2655. ifdef SMPKERNEL
  2656.       cmp      _PGEnabled,1
  2657.       jz      short l0
  2658.       add      reg,[_TKSSBase1]                       ;whs
  2659.       jmp      short l1
  2660.        assume ds:FLAT
  2661.      l0:
  2662. endif
  2663.       add      reg,[_TKSSBase]                       ;whs
  2664.      l1:                                   ;whs
  2665.     endm                                   ;whs
  2666. endif
  2667.                                        ;whs
  2668. ;*** DSToSS_PS - Convert DS-relative offset to SS-relative offset (priva te;whs
  2669. ;                                       ;whs
  2670. ;   ENTRY                                   ;whs
  2671. ;    reg - register containing offset to be converted           ;whs
  2672. ;    val - optional memory location to take offset of (if not in reg     al;whs
  2673. ;                                       ;whs
  2674. ;   USES                                   ;whs
  2675. ;    reg, Flags                               ;whs
  2676.  
  2677. ifndef SMP
  2678. DSToSS_PS  macro   reg,val                           ;whs
  2679. local    l1                                   ;whs
  2680.     ifnb    <val>                               ;whs
  2681.       lea      reg,val                           ;whs
  2682.     endif                                   ;whs
  2683.       push      ax                               ;whs
  2684.       mov      ax,ss                               ;whs
  2685.       cmp      ax,seg FLAT:DGROUP                       ;whs
  2686.       pop      ax                               ;whs
  2687.       je      l1                               ;whs
  2688.       sub      reg,[_TKSSBase]                       ;whs
  2689.      l1:                                   ;whs
  2690.     endm                                   ;whs
  2691. else
  2692. DSToSS_PS  macro   reg,val                           ;whs
  2693. local    l0,l1
  2694.     ifnb    <val>                               ;whs
  2695.       lea      reg,val                           ;whs
  2696.     endif                                   ;whs
  2697.       push      ax                               ;whs
  2698.       mov      ax,ss                               ;whs
  2699.       cmp      ax,seg FLAT:DGROUP                       ;whs
  2700.       pop      ax                               ;whs
  2701.       je      l1                               ;whs
  2702. ifdef SMPKERNEL
  2703.       cmp      _PGEnabled,1
  2704.       jz      short l0
  2705.       sub      reg,[_TKSSBase1]                       ;whs
  2706.       jmp      short l1
  2707.        assume ds:FLAT
  2708.      l0:
  2709. endif
  2710.       sub      reg,[_TKSSBase]                       ;whs
  2711.      l1:                                   ;whs
  2712.     endm                                   ;whs
  2713. endif
  2714.                                        ;whs
  2715.  
  2716. ;*** SSToDS - Convert SS-relative offset to DS-relative offset
  2717. ;
  2718. ;   ENTRY
  2719. ;    reg - register containing offset to be converted
  2720. ;    val - optional memory location to take offset of (if not in reg already)
  2721. ;
  2722. ;   USES
  2723. ;    reg, Flags
  2724. ;
  2725.  
  2726. ifndef SMP
  2727. SSToDS    macro    reg,val
  2728.     ifnb    <val>
  2729.       lea      reg,val
  2730.     endif
  2731.       add      reg,[_TKSSBase]
  2732.     endm
  2733. else
  2734. SSToDS    macro    reg,val
  2735. local l0,l1
  2736.     ifnb    <val>
  2737.       lea      reg,val
  2738.     endif
  2739. ifdef SMPKERNEL
  2740.       cmp      _PGEnabled,1
  2741.       jz      short l0
  2742.       add      reg,[_TKSSBase1]                       ;whs
  2743.       jmp      short l1
  2744.        assume ds:FLAT
  2745.      l0:
  2746. endif
  2747.       add      reg,[_TKSSBase]
  2748.      l1:
  2749.     endm
  2750. endif
  2751.  
  2752. ;*** DSToSS - Convert DS-relative offset to SS-relative offset
  2753. ;
  2754. ;   ENTRY
  2755. ;    reg - register containing offset to be converted
  2756. ;    val - optional memory location to take offset of (if not in reg already)
  2757. ;
  2758. ;   USES
  2759. ;    reg, Flags
  2760.  
  2761. ifndef SMP
  2762. DSToSS    macro    reg,val
  2763.     ifnb    <val>
  2764.       lea      reg,val
  2765.     endif
  2766.       sub      reg,[_TKSSBase]
  2767.     endm
  2768. else
  2769. DSToSS    macro    reg,val
  2770. local l0,l1
  2771.     ifnb    <val>
  2772.       lea      reg,val
  2773.     endif
  2774. ifdef SMPKERNEL
  2775.       cmp      _PGEnabled,1
  2776.       jz      short l0
  2777.       sub      reg,[_TKSSBase1]                       ;whs
  2778.       jmp      short l1
  2779.        assume ds:FLAT
  2780.      l0:
  2781. endif
  2782.       sub      reg,[_TKSSBase]
  2783.      l1:
  2784.     endm
  2785. endif
  2786.  
  2787. ;*** PopAll - pop user's registers
  2788. ;
  2789.  
  2790. PopAll    macro
  2791.     .386p
  2792.     popad
  2793.     pop    gs
  2794.     pop    fs
  2795.     CPUMode reset
  2796.     pop    es
  2797.     pop    ds
  2798. endm
  2799.  
  2800. ;*** PushAll - push user's registers
  2801. ;
  2802.  
  2803. PushAll macro
  2804.     push    ds
  2805.     push    es
  2806.     .386p
  2807.     push    fs
  2808.     push    gs
  2809.     pushad
  2810.     CPUMode reset
  2811. endm
  2812.  
  2813. ;*** IODELAY - generate delay between I/O instructions
  2814. ;
  2815. ;   Use this between two adjacent I/O instructions.
  2816. ;
  2817. ;   EXIT    Code generated to cause a slight delay.
  2818.  
  2819. IODELAY macro
  2820.     jmp    short $+2
  2821. endm
  2822.  
  2823. ;*** RETD - Default 32-bit return
  2824. ;
  2825.  
  2826. RETD    macro    nparms
  2827.     ?RET <ne>, <ret>, <nparms>
  2828. endm
  2829.  
  2830. ;*** RETND - Near 32-bit return
  2831. ;
  2832.  
  2833. RETND    macro    nparms
  2834.     ?RET <ne>, <retn>, <nparms>
  2835. endm
  2836.  
  2837. ;*** RETFD - Far 32-bit return
  2838. ;
  2839.  
  2840. RETFD    macro    nparms
  2841.     ?RET <ne>, <retf>, <nparms>
  2842. endm
  2843.  
  2844. ;*** RETW - Default 16-bit return
  2845. ;
  2846.  
  2847. RETW    macro    nparms
  2848.     ?RET <eq>, <ret>, <nparms>
  2849. endm
  2850.  
  2851. ;*** RETNW - Near 16-bit return
  2852. ;
  2853.  
  2854. RETNW    macro    nparms
  2855.     ?RET <eq>, <retn>, <nparms>
  2856. endm
  2857.  
  2858. ;*** RETFW - Far 16-bit return
  2859. ;
  2860.  
  2861. RETFW    macro    nparms
  2862.     ?RET <eq>, <retf>, <nparms>
  2863. endm
  2864.  
  2865. ;*** ?RET - RET* worker macro
  2866. ;
  2867.  
  2868. ?RET    macro    rel, retinst, nparms
  2869.     if (?cstype rel ?CS_32bit)
  2870.     db    MI_OPERANDSIZE
  2871.     endif
  2872.     retinst nparms
  2873. endm
  2874.  
  2875. ;*** PUSHD - push dword value no matter the code segment type
  2876. ;
  2877. ;   Normally immediate and segment registers push a word or
  2878. ;   dword on the stack depending on the code segment type.  This
  2879. ;   macro always pushes the "value" as a dword (unless "value" is
  2880. ;   a 16 bit register).
  2881. ;
  2882. ;   ENTRY   value
  2883. ;
  2884. ;   EXIT    NONE
  2885. ;
  2886. ;   USES    NONE
  2887.  
  2888. PUSHD    macro    value, testarg
  2889.     if2
  2890.     .errnb <testarg>            ;; too many args
  2891.     irp x,<ax,bx,cx,dx,si,di,bp,sp>
  2892.         ifidni <x>,<value>
  2893.         ProcError <PUSHD: 16 bit register: x>
  2894.         .err
  2895.         endif
  2896.     endm
  2897.     endif
  2898.     ?bm1 = .type value                ;; helps debug the macro
  2899.     ?bm1 = 2                    ;; use simple push
  2900.     if (?cstype ne ?CS_32bit)
  2901.     ?bm1 = 0                ;; use dword ptr push
  2902.     irp x,<cs,ds,es,fs,gs,ss>
  2903.         ifidni <x>,<value>
  2904.         ?bm1 = 1            ;; use explicit override
  2905.         endif
  2906.     endm
  2907.     if (?bm1 eq 0)
  2908.         if (((.type (value)) and 07h) eq 04h) ;; if simple constant
  2909.         if ((value) lt 128) and ((value) gt -129)
  2910.             ?bm1 = 1            ;; use explicit override
  2911.         endif
  2912.         elseif ((.type (value)) and 10h)    ;; if register
  2913.         ?bm1 = 2            ;; use simple push
  2914.         endif
  2915.     endif
  2916.     endif
  2917.     if (?bm1 eq 0)
  2918.     push    dword ptr (value)
  2919.     else
  2920.     if (?bm1 eq 1)                ;; explicit override
  2921.         db    MI_OPERANDSIZE
  2922.     endif
  2923.     push    value
  2924.     endif
  2925. endm
  2926.  
  2927. ;*** POPD - pop dword value no matter the code segment type
  2928. ;
  2929. ;   Normally segment registers pop a word or dword on the stack
  2930. ;   depending on the code segment type.  This macro always popes
  2931. ;   the "value" as a dword (unless "value" is a 16 bit register).
  2932. ;
  2933. ;   ENTRY   value
  2934. ;
  2935. ;   EXIT    NONE
  2936. ;
  2937. ;   USES    NONE
  2938.  
  2939. POPD    macro    value, testarg
  2940.     if2
  2941.     .errnb <testarg>            ;; too many args
  2942.     irp x,<ax,bx,cx,dx,si,di,bp,sp>
  2943.         ifidni <x>,<value>
  2944.         ProcError <POPD: 16 bit register: x>
  2945.         .err
  2946.         endif
  2947.     endm
  2948.     endif
  2949.     ?bm1 = .type value                ;; helps debug the macro
  2950.     ?bm1 = FALSE
  2951.     if (?cstype eq ?CS_32bit)
  2952.     pop    value
  2953.     else
  2954.     irp x,<cs,ds,es,fs,gs,ss>
  2955.         ifidni <x>,<value>
  2956.         db    MI_OPERANDSIZE
  2957.         pop    value
  2958.         ?bm1 = TRUE
  2959.         endif
  2960.     endm
  2961.     if ?bm1 eq FALSE
  2962.         if ((.type value) and 10h)    ;; if register
  2963.         pop    value
  2964.         else
  2965.         pop    dword ptr value
  2966.         endif
  2967.     endif
  2968.     endif
  2969. endm
  2970.  
  2971. ;   This section contains macros to get around the 386 chip bug
  2972. ;   regarding use of LSL, LAR, VERR, and VERW instructions.
  2973. ;
  2974. ;   If a bad selector is passed to any instruction above, it may
  2975. ;   cause the 386 processor to hang up after executing the
  2976. ;   instruction.  A workaround for this is to follow the instructions
  2977. ;   with a jmp, and have the last byte of instructions aligned in the
  2978. ;   same dword as all of jmp instruction; so that both instructions will
  2979. ;   be prefetched together.
  2980. ;
  2981. ;   BUGBUG:  The code segments used must be DWORD aligned in order for
  2982. ;   these macros to work properly.  There is an ALIGN 4 directive in
  2983. ;   the ?Bug386 macro that should help insure this (however, the assembler
  2984. ;   only seems to complain if the align-type is BYTE;  WORD works, but
  2985. ;   musn't be allowed).
  2986. ;
  2987.  
  2988. ;*** LOADSL - Macro to replace 'lsl reg,sel'
  2989. ;
  2990.  
  2991. LOADSL    macro    reg,sel
  2992.     .errb <reg>
  2993.     .errb <sel>
  2994.     ?Bug386 lsl,<reg>,sel
  2995. endm
  2996.  
  2997. ;*** LOADAR - Macro to replace 'lar reg,sel'
  2998. ;
  2999.  
  3000. LOADAR    macro    reg,sel
  3001.     .errb <reg>
  3002.     .errb <sel>
  3003.     ?Bug386 lar,<reg>,sel
  3004. endm
  3005.  
  3006. ;*** VERIFYREAD - Macro to replace 'verr sel'
  3007. ;
  3008. ;   The second variable is a scratch register which improves
  3009. ;   performance if provided and sel is not a register variable.
  3010. ;
  3011.  
  3012. VERIFYREAD macro    sel,screg
  3013.     .errb <sel>
  3014.     ?Bug386 verr,,<sel>,screg
  3015. endm
  3016.  
  3017. ;*** VERIFYWRITE - Macro to replace 'verw sel'
  3018. ;
  3019. ;   The second variable is a scratch register which improves
  3020. ;   performance if provided and sel is not a register variable.
  3021. ;
  3022.  
  3023. VERIFYWRITE macro   sel,screg
  3024.     .errb <sel>
  3025.     ?Bug386 verw,,<sel>,screg
  3026. endm
  3027.  
  3028. ;*** ?Bug386
  3029. ;
  3030. ;   This macro provides a workaround the 386 chip bug
  3031. ;   that causes the processor to hang if a bad selector
  3032. ;   is passsed to any of the instructions lsl, lar, verr,
  3033. ;   and verw. It puts the last byte of the given instruction
  3034. ;   in the same dword with the following jnz instruction
  3035. ;
  3036.  
  3037. ?Bug386 macro    inst,reg,sel,screg
  3038.     local zero
  3039.     ?bm1 = TRUE
  3040.     irp x,<ax,bx,cx,dx,si,di>
  3041.     ifidni <sel>,<x>        ;; Is sel a register?
  3042.         ?bm1 = FALSE
  3043.         exitm
  3044.     endif
  3045.     endm
  3046.     ifnb <reg>                ;; if it is lsl or lar
  3047.     irp x,<eax,ebx,ecx,edx,esi,edi>
  3048.         ifidni <sel>,<x>        ;; 32 bit registers are also OK
  3049.         ?bm1 = FALSE
  3050.         exitm
  3051.         endif
  3052.     endm
  3053.     endif
  3054.     if ?bm1                ;; Set up sel in a register
  3055.     ifb <reg>            ;; if it is verr or verw
  3056.         ifb <screg>            ;; if no scratch register
  3057.         push  ax        ;; save ax
  3058.         mov   ax,sel        ;; (ax) = sel
  3059.         else            ;; else use scratch register
  3060.         mov   screg,sel
  3061.         endif
  3062.     else                ;; if it is lsl or lar
  3063.         mov     reg,sel
  3064.     endif
  3065.     endif
  3066.  
  3067.     ?i = $
  3068.     org 0
  3069.     zero label near
  3070.     align 4                ;; the "align" is superfluous at
  3071.                     ;; offset 0;  idea is to try to insure
  3072.                     ;; proper segment align-type (DWORD)
  3073.     org ?i
  3074.     ?i = ($ - offset cs:zero) mod 4    ;; calculate how many
  3075.     ?i = (6 - ?i) mod 4            ;; NOPS needed for padding
  3076.     rept ?i
  3077.     nop
  3078.     endm
  3079.     ?i = $                ;; this label must be odd-word aligned
  3080.     if ?bm1
  3081.     ifb <reg>            ;; If it is verr or verw
  3082.         ifb <screg>            ;; No scratch register
  3083.         inst  ax
  3084.         else            ;; use scratch register
  3085.         inst  screg
  3086.         endif
  3087.     else
  3088.         inst  reg,reg        ;; lsl or lar
  3089.     endif
  3090.     else
  3091.     ifb <reg>
  3092.         inst  sel
  3093.     else
  3094.         inst  reg,sel
  3095.     endif
  3096.     endif
  3097.     jmp short $+2            ;; Must be in the same dword with the
  3098.                     ;; last byte of previous instruction
  3099.     if ($ - ?i - 5)
  3100.     if ($ - ?i - 6)
  3101.         .err            ;; Len must be 5 bytes (6 if 32bit reg)
  3102.     endif
  3103.     endif
  3104.     if ?bm1                  ;; Did we push ax?
  3105.     ifb <reg>
  3106.         ifb <screg>
  3107.         pop  ax
  3108.         endif
  3109.     endif
  3110.     endif
  3111. endm
  3112.  
  3113. ;***    B1EMac - 386 B1 Errata Macro
  3114. ;
  3115. ;    This macro generates workarounds for the erratum 7 on the 386 B1
  3116. ;    errata sheet dated September 1 1987:
  3117. ;
  3118. ;    <Begin Quote:>
  3119. ;    Wrong Register Size for String Instructions in Mixed 16/32-bit
  3120. ;    Addressing Systems.
  3121. ;
  3122. ;    Problem:  If certain string and loop instructions are followed by
  3123. ;    instructions that either:
  3124. ;
  3125. ;    1)  use a different address size (that is, if either the string
  3126. ;        instruction or the following instruction uses an address size
  3127. ;        prefix), or
  3128. ;
  3129. ;    2)  reference the stack (e.g. PUSH/POP/CALL/RET) and the "B" bit
  3130. ;        in the SS descriptor is different from the address size used
  3131. ;        by the string instructions,
  3132. ;
  3133. ;    then one or more of (E)CX, (E)SI, or (E)DI is not updated properly.
  3134. ;    The size of the register (16 vs. 32) is taken from the following
  3135. ;    instruction rather than the from the string or loop instruction.
  3136. ;    This could result in updating only the lower 16 bits of a 32 bit
  3137. ;    register, or in updating all 32 bits of a register being used as
  3138. ;    16 bits.  The instructions and registers affected by this are listed
  3139. ;    below:
  3140. ;
  3141. ;        Instruction    Register(s)
  3142. ;            MOVS      (E)DI
  3143. ;            REP MOVS      (E)SI
  3144. ;            STOS      (E)DI
  3145. ;            INS          (E)DI
  3146. ;            REP INS      (E)CX
  3147. ;
  3148. ;    Workaround: No workaround is necessary if all code is 16-bit or if
  3149. ;    all code is 32-bit.  The problem only occurs if instructions with
  3150. ;    different address sizes are mixed together, or if a code segment of
  3151. ;    one size used with a stack segment of the other size.
  3152. ;
  3153. ;    In a system which mixes address sizes, add a NOP after each of the
  3154. ;    above instrcutions and ensure that the NOP has the same address
  3155. ;    size as the string/loop (i.e., if the string/loop instruction
  3156. ;    includes as address prefix, place the same address prefix before
  3157. ;    the NOP; conversely, if the string/loop instruction does not have
  3158. ;    an address prefix, do not place a prefix before the NOP).
  3159. ;    <End Quote>
  3160. ;
  3161. ;    Invocation examples:
  3162. ;        B1EMac   insb
  3163. ;        B1EMac   repne ins dword ptr es:[di],dx
  3164. ;        B1EMac   rep movsw
  3165. ;        B1EMac   movs byte ptr es:[edi],byte ptr gs:[esi]
  3166. ;        B1EMac   stos dword ptr es:[di]
  3167. ;    No white space is allowed on either size of the colons or on either
  3168. ;    side of the registers within square brackets ("es:[edi]" must be one
  3169. ;    token).
  3170. ;
  3171. ;    ENTRY    reparg    = <blank>,rep,repne,etc.    (optional)
  3172. ;        instr    = ins*,movs*,stos*
  3173. ;        dstsize = <blank>,byte,word,dword
  3174. ;        dstptr    = <blank>,ptr
  3175. ;        dstreg    = <blank>,es:[di],es:[edi]
  3176. ;        srcsize = <blank>,byte,word,dword
  3177. ;        srcptr    = <blank>,ptr
  3178. ;        srcreg    = <blank>,?s:[si],?s:[esi]
  3179. ;        testarg = <blank>
  3180. ;    (global variables)
  3181. ;        ?cstype = ?CS_32bit or 0 to indicate default address size
  3182. ;
  3183. ;    EXIT    code generated to invoke the instruction with workaround
  3184.  
  3185. ?BE_REP      equ 0001h    ; valid rep prefix
  3186. ?BE_LONG  equ 0002h    ; long form of instruction
  3187. ?BE_SHORT  equ 0004h    ; short form of instruction
  3188.  
  3189. B1EMac    macro  reparg,instr,dstsize,dstptr,dstreg,srcsize,srcptr,srcreg,testarg
  3190.     if2
  3191.     .errnb <testarg>            ;; too many args
  3192.     endif
  3193.     ?bm1 = 0
  3194.     ?bm2 = ?cstype                ;; assume default address size
  3195.     ifnb <reparg>
  3196.     irp reptmp,<rep,repe,repz,repne,repnz>    ;; valid rep prefix?
  3197.         ifidni <reparg>,<reptmp>
  3198.         ?bm1 = ?bm1 or ?BE_REP        ;; Yes.
  3199.         endif
  3200.     endm
  3201.     if ((?bm1 and ?BE_REP) eq 0)        ;; else reinvoke with blank rep
  3202.         B1EMac <> reparg instr dstsize dstptr dstreg, srcsize srcptr srcreg
  3203.         exitm                ;; and terminate the macro
  3204.     endif
  3205.     endif
  3206.     irp insttmp,<movs,ins,stos>            ;; long form of instruction?
  3207.     ifidni <instr>,<insttmp>
  3208.         ?bm1 = ?bm1 or ?BE_LONG        ;; Yes.
  3209.     endif
  3210.     endm
  3211.     if (?bm1 and ?BE_LONG)            ;; long form?
  3212.     ifidni <dstreg>,<es:[edi]>
  3213.         ?bm2 = ?CS_32bit            ;; 32-bit address size
  3214.     elseifidni <dstreg>,<es:[di]>
  3215.         ?bm2 = 0                ;; 16-bit address size
  3216.     elseif2
  3217.         ifb <dstreg>
  3218.         %out B1EMac: destination register required
  3219.         else
  3220.         %out B1EMac: bad destination register: dstreg
  3221.         endif
  3222.         .err
  3223.     endif
  3224.     else                    ;; else valid short form?
  3225.     irp insttmp,<movsb,movsw,movsd,insb,insw,insd,stosb,stosw,stosd>
  3226.         ifidni <instr>,<insttmp>
  3227.         ?bm1 = ?bm1 or ?BE_SHORT    ;; Yes.
  3228.         endif
  3229.     endm
  3230.     if ((?bm1 and ?BE_SHORT) eq 0)
  3231.         if2
  3232.         %out B1EMac: bad instruction: instr
  3233.         .err
  3234.         endif
  3235.     endif
  3236.     endif
  3237.     ifnb <srcsize>                ;; comma required?
  3238.     reparg instr dstsize dstptr dstreg, srcsize srcptr srcreg
  3239.     else
  3240.     reparg instr dstsize dstptr dstreg
  3241.     endif
  3242.     if (?bm2 ne (?cstype and ?CS_32bit))    ;; add override if needed
  3243.     db    MI_ADDRESSSIZE
  3244.     endif
  3245.     nop
  3246. endm
  3247.  
  3248. ;***    btrx, btsx, orb, andb, testb, etc.
  3249. ;
  3250. ;    These macros allow you to generate more space-efficient 386 code,
  3251. ;    by oring/anding/testing only individual bytes of dwords, provided the
  3252. ;    mask (source operand) contains bits in exactly one byte; eg,
  3253. ;
  3254. ;        test    [foo],00000000000000001111111100000000b
  3255. ;
  3256. ;    can be written as
  3257. ;
  3258. ;        testb   [foo],00000000000000001111111100000000b
  3259. ;
  3260. ;    which will automatically generate the following:
  3261. ;
  3262. ;        test    byte ptr [foo+1],11111111b
  3263. ;
  3264. ;    The btrx and and btsx macros simply let you feed a normal bitmask
  3265. ;    into a btr or bts instruction, instead of a bit offset (which we
  3266. ;    generally don't have equates for).
  3267. ;
  3268.  
  3269. orb    macro    dst,src
  3270.     ?ins    or,dst,src,0
  3271.     endm
  3272.  
  3273. andb    macro    dst,src
  3274.     ?ins    and,dst,src,0ffh
  3275.     endm
  3276.  
  3277. clrb    macro    dst,src
  3278.     ?ins    and,dst,%(not src),0ffh
  3279.     endm
  3280.  
  3281. xorb    macro    dst,src
  3282.     ?ins    xor,dst,src,0
  3283.     endm
  3284.  
  3285. testb    macro    dst,src
  3286.     ?ins    test,dst,src,0
  3287.     endm
  3288.  
  3289. ?ins    macro    ins,dst,src,b
  3290.     ?bm1 = 0
  3291.     ?bm2 = 0
  3292.     ?bm3 = 0ffh
  3293.     ?bm4 = b
  3294.     rept 4
  3295.       if (src and ?bm3) ne ?bm4
  3296.         ?bm5 = ?bm1
  3297.         ?bm2 = ?bm2 + 1
  3298.       endif
  3299.       ?bm1 = ?bm1 + 1
  3300.       ?bm3 = ?bm3 shl 8
  3301.       ?bm4 = ?bm4 shl 8
  3302.     endm
  3303.     if (?bm2 ne 1)
  3304.     ins    dst,src
  3305.     else
  3306.     ?insx    ins,dst,src,%?bm5
  3307.     endif
  3308.     endm
  3309.  
  3310. ?insx    macro    ins,dst,src,i
  3311.     ins    byte ptr dst+i,src shr (i*8)
  3312.     endm
  3313.  
  3314. btx    macro    dst,src
  3315.     ?bitno    src
  3316.     bt    dst,?bm1
  3317.     endm
  3318.  
  3319. btcx    macro    dst,src
  3320.     ?bitno    src
  3321.     btc    dst,?bm1
  3322.     endm
  3323.  
  3324. btrx    macro    dst,src
  3325.     ?bitno    src
  3326.     btr    dst,?bm1
  3327.     endm
  3328.  
  3329. btsx    macro    dst,src
  3330.     ?bitno    src
  3331.     bts    dst,?bm1
  3332.     endm
  3333.  
  3334. ?bitno    macro    m
  3335.     ?bm1 = 0
  3336.     ?bm2 = m
  3337.     rept 32
  3338.       ?bm2 = ?bm2 shr 1
  3339.       if ?bm2 ne 0
  3340.         ?bm1 = ?bm1 + 1
  3341.       endif
  3342.     endm
  3343.     endm
  3344.  
  3345.  
  3346. ;***    GenHybrid - generate a far entry header for a faronly procedure
  3347. ;***    ?Gen16 - generate a far entry header for a far16 procedure
  3348. ;***    GenFar32 - generate a far entry header for a far32 procedure
  3349. ;
  3350. ;    A faronly/far16/far32 procedure is constructed by creating a
  3351. ;    faronly/far16/far32 entry header followed by a near procedure.
  3352. ;
  3353. ;   ENTRY   name = name of procedure
  3354. ;        lcl     = blank - make the far entry point public
  3355. ;         = non-blank - if symbol NOLOCAL is defined, then
  3356. ;                   the entry is made public anyway.
  3357. ;                   Else it is made 'local' by renaming
  3358. ;                   it into lxx_&name (xx is a unique
  3359. ;                   number) and declared public. This is
  3360. ;                   useful for symbolic debugging.
  3361. ;        usecall = blank - assume that this thunk immediately
  3362. ;                  precedes the real function, and that
  3363. ;                  control can fall through
  3364. ;            = non-blank - assume that another thunk will be
  3365. ;                  between this one and the real function,
  3366. ;                  so we must use a CALL to invoke it.  Note
  3367. ;                  that this precludes the use of ArgVar.
  3368. ;        (global vars)
  3369. ;        NOLOCAL = undefined - let lcl controls whether the
  3370. ;                      entry point should be (fake)
  3371. ;                      local or public.
  3372. ;            = defined - make entry point public no matter
  3373. ;                    what "lcl" is.
  3374. ;
  3375. ;   EXIT    A far entry header (code and pseudo ops) generated.
  3376. ;        A "public" pseudo op is generated to declare the
  3377. ;        entry point public or local (fake local).
  3378.  
  3379. GenHybrid macro name, lcl, usecall, half
  3380.     ?GenThunk <RETFOFFSET>, <RETFOFFSET>, <retf>, %HYBPRE_, <name>, <lcl>, <usecall>, <half>
  3381. endm
  3382.  
  3383. ?Gen16 macro name, lcl, usecall
  3384.     ?GenThunk <RETFDOFFSET>, <RETFDOFFSET>, <RETFD>, %F16PRE_, <name>, <lcl>, <usecall>
  3385. endm
  3386.  
  3387. GenFar32 macro name, lcl, usecall, half
  3388.     if2
  3389.     ifndef RETFDLabel
  3390.         extrn RETFDLabel:near
  3391.     endif
  3392.     endif
  3393.     ?GenThunk <RETFDOFFSET>, <offset FLAT:RETFDLabel>, <retf>, %F32PRE_, <name>, <lcl>, <usecall>, <half>
  3394. endm
  3395.  
  3396. ?GenThunk macro fretdef, retoffset, retinst, prefix, name, lcl, usecall, half
  3397.     local a
  3398.     ?bm1 = 3
  3399.     ifnb <half>
  3400.     ?bm1 = 0
  3401.     irp x,<half>
  3402.         ifidn <x>,<tolabel>
  3403.         ?bm1 = ?bm1 or 1
  3404.         elseifidn <x>,<afterlabel>
  3405.         ?bm1 = ?bm1 or 2
  3406.         elseif2
  3407.         %out bad half_arg to ?GenThunk: half
  3408.         .err
  3409.         endif
  3410.     endm
  3411.     endif
  3412.     if (?bm1 and 1)
  3413.     ifndef fretdef
  3414.         a:    retinst
  3415.     endif
  3416.     GenPublic prefix&name,<lcl>,<code> ;; generate a public or local symbol
  3417.     prefix&name label far
  3418.     endif
  3419.     if (?bm1 and 2)
  3420.     ifb <usecall>
  3421.         ifdef fretdef
  3422.         push  retoffset        ;; near-code must immediately follow
  3423.         else
  3424.         push  offset cs:a    ;; near-code must immediately follow
  3425.         endif
  3426.     else
  3427.         call    name
  3428.         retinst
  3429.     endif
  3430.     endif
  3431. endm
  3432.  
  3433. ifdef INCL_DEF
  3434.  
  3435. ;*** ?Alloc - Allocate well-aligned data
  3436. ;
  3437.  
  3438. ?Alloc    macro var,dtyp,val,f
  3439.       ifndef NOALIGN
  3440.         if ?cstype EQ ?CS_16bit
  3441.           ifidni <dtyp>,<dw>
  3442.         ?Align var,2
  3443.           elseif f
  3444.         ?Align var,2        ;; align structures as well
  3445.           endif
  3446.         elseif ?cstype EQ ?CS_32bit
  3447.           ifidni <dtyp>,<dd>
  3448.         ?Align var,4
  3449.           elseif f
  3450.         ?Align var,4        ;; align structures as well
  3451.           endif
  3452.         endif
  3453.       endif
  3454.       var dtyp val
  3455. endm
  3456.  
  3457. ;*** ?Align - Insure alignment is as specified
  3458. ;
  3459.  
  3460. ?Align    macro var,b
  3461.       ?bm1 = offset $
  3462.       ALIGN b
  3463.       if ?bm1 NE offset $
  3464.         ifnb <var>
  3465.           if1
  3466.         %out b-byte alignment adjustment:  var
  3467.           endif
  3468.         endif
  3469.       endif
  3470. endm
  3471.  
  3472. ;*** REALEVEN - This macro replaces EVEN when we have offsets
  3473. ;        above 32k in a segment. It is used in pdata.asm
  3474. ;        and is required because the current version of
  3475. ;        masm (5.10A.06) has a bug which makes it put
  3476. ;        3 bytes of padding rather than 1.
  3477. ;        If we change to a version of the assembler
  3478. ;        without this bug, we can remove this macro.
  3479.  
  3480. REALEVEN macro
  3481.  
  3482.     ?intgr = ($- TASKAREA:BASEPTDA) mod 2
  3483.  
  3484.     REPT    ?intgr
  3485.         db    0
  3486.     ENDM
  3487.  
  3488. endm
  3489.  
  3490. ;*** ?SetType - Set ?cstype to value specified
  3491. ;
  3492.  
  3493. ?SetType macro val
  3494.        ifdif <val>,<USE32>
  3495.          ?cstype = ?CS_16bit
  3496.        else
  3497.          ?cstype = ?CS_32bit
  3498.        endif
  3499. endm
  3500.  
  3501. ;*** ?PushSeg - Save segment state
  3502. ;
  3503.  
  3504. ?PushSeg macro n
  3505.     ifdif <n>,<0>
  3506.       ?segname&n catstr ?segname
  3507.       ?curseg&n catstr ?curseg
  3508.       ?cstype&n = ?cstype
  3509.       ?model&n = ?model
  3510.       ?declare&n = ?declare
  3511.     endif
  3512. endm
  3513.  
  3514. ;*** ?PopSeg - Restore segment state
  3515. ;
  3516.  
  3517. ?PopSeg macro n
  3518.     ifdif <n>,<0>
  3519.       ?segname catstr ?segname&n
  3520.       ?curseg catstr ?curseg&n
  3521.       ?cstype = ?cstype&n
  3522.       ?model = ?model&n
  3523.       ?declare = ?declare&n
  3524.     else
  3525.       ?segname equ <>
  3526.       ?curseg equ <>
  3527.       ?cstype = NULL
  3528.       ?model = NULL
  3529.       ?declare = NULL
  3530.     endif
  3531. endm
  3532.  
  3533. ;*** ?OpenSeg - Parse parameters to DefCode/DefData
  3534. ;
  3535.  
  3536. ?OpenSeg macro scope,class,model,type
  3537.       ?declare = NULL
  3538.       ifidni <scope>,<EXPORT>
  3539.         ?declare = ?PUBLIC
  3540.       elseifidni <scope>,<IMPORT>
  3541.         ?declare = ?EXTRN
  3542.       elseifdifi <scope>,<LOCAL>
  3543.        ifdef DEBUG
  3544.         if DEBUG eq 1
  3545.           ?declare = ?PUBLIC
  3546.         endif
  3547.        endif
  3548.       endif
  3549.       ifidni <model>,<C>
  3550.         ?model = ?C
  3551.       elseifidni <model>,<PASCAL>
  3552.         ?model = ?PASCAL
  3553.       else
  3554.         ?model = NULL
  3555.       endif
  3556.       ?nsegs = ?nsegs + 1
  3557.       % ifidni <?curseg>,<?segname>
  3558.         ?segname equ <>
  3559.       else
  3560.         ?Eval %?segname,segment
  3561.         ?curseg catstr ?segname
  3562.       endif
  3563. endm
  3564.  
  3565. ;*** ?CloseSeg - Parse parameters to EndCode/EndData
  3566. ;
  3567.  
  3568. ?CloseSeg macro scope,class,model,type,m
  3569.       % ifnb <?segname>
  3570.         ?Eval %?segname,ends
  3571.       endif
  3572.       if ?nsegs EQ 0
  3573.         if1
  3574.           %out Missing m directive
  3575.         endif
  3576.       else
  3577.         ?nsegs = ?nsegs - 1
  3578.       endif
  3579. endm
  3580.  
  3581. ;*** ?ToUpper - Converts string to upper-case, returned in ?upper
  3582. ;
  3583.  
  3584. ?ToUpper macro s
  3585.       ?upper equ <>
  3586.       irpc x,<s>
  3587.         if '&x' GE 'a'
  3588.           if '&x' LE 'z'
  3589.         ?t1 substr <ABCDEFGHIJKLMNOPQRSTUVWXYZ>,'&x'-'a'+1,1
  3590.         ?upper catstr ?upper,?t1
  3591.           else
  3592.         ?upper catstr ?upper,<&x>
  3593.           endif
  3594.         else
  3595.           ?upper catstr ?upper,<&x>
  3596.         endif
  3597.       endm
  3598.     endm
  3599.  
  3600. endif ; INCL_DEF
  3601.  
  3602. ;*** ?DefLabel - define a label using text-macro arguments
  3603. ;
  3604.  
  3605. ?DefLabel macro var,type
  3606.       .lall
  3607.       var label type
  3608.       .xall
  3609.     endm
  3610.  
  3611. ;*** ?DefExtrn - define an external using text-macro arguments
  3612. ;
  3613.  
  3614. ?DefExtrn macro var,type
  3615.       .lall
  3616.       extrn var:type
  3617.       .xall
  3618.     endm
  3619.  
  3620. ;*** ?DefPublic - define a public using text-macro arguments
  3621. ;
  3622.  
  3623. ?DefPublic macro var
  3624.       .lall
  3625.       public var
  3626.       .xall
  3627.     endm
  3628.  
  3629. ;*** ?DefField - define a field, and make it public if DEBUG defined true
  3630. ;
  3631.  
  3632. ?DefField macro fn,var,stmt
  3633.         ?F&fn macro
  3634.         var stmt
  3635.         endm
  3636.         ifdef DEBUG
  3637.           if DEBUG eq 1
  3638.         ifnb <var>
  3639.           ?D&fn macro
  3640.           public _&var
  3641.           _&var = var
  3642.           endm
  3643.         endif
  3644.           endif
  3645.         endif
  3646.       endm
  3647.  
  3648. ;*** ?Eval - Evaluates text-macros for readability in listings
  3649. ;
  3650.  
  3651. ?Eval    macro ins,a1,a2,a3,a4
  3652.       ifb <a3>
  3653.     ifb <a2>
  3654.       ins    a1
  3655.     else
  3656.       ins    a1,a2
  3657.     endif
  3658.       else
  3659.       ins    a1,[a2&a3&a4]
  3660.       endif
  3661. endm
  3662.  
  3663. ;*** ?BPEqu - Creates an equate for referencing vars via BP/EBP/ESP
  3664. ;
  3665.  
  3666. ?BPEqu    macro sym,typ,bpr,s,a
  3667.     ifb <typ>
  3668.       ifdifi <bpr>,<esp>
  3669.         .lall
  3670.         sym equ <[bpr&s&a]>
  3671.         .xall
  3672.       else
  3673.         .lall
  3674.         sym equ <[bpr&s&a+?stackdepth]>
  3675.         .xall
  3676.       endif
  3677.     else
  3678.       ifdifi <bpr>,<esp>
  3679.         .lall
  3680.         sym equ <(typ ptr [bpr&s&a])>
  3681.         .xall
  3682.       else
  3683.         .lall
  3684.         sym equ <(typ ptr [bpr&s&a+?stackdepth])>
  3685.         .xall
  3686.       endif
  3687.     endif
  3688.     endm
  3689.  
  3690. ;*** ?Arg - Processes argument list - used by CCall only
  3691. ;
  3692.  
  3693. ?Arg    macro    arglst
  3694.       irp x,<arglst>
  3695.         ?argc = ?argc + 1
  3696.         ?MArg push,<x>,%?argc
  3697.       endm
  3698.       ?bm1 = ?argc
  3699.       rept ?bm1
  3700.         ?InvPrg <?AM>,%?bm1
  3701.         ?bm1 = ?bm1 - 1
  3702.       endm
  3703.     endm
  3704.  
  3705. ;*** ?MArg - Makes a macro to do the specified operation
  3706. ;
  3707.  
  3708. ?MArg    macro    op,arg,num
  3709.       ?AM&num ¯o
  3710.       op  arg
  3711.       &endm
  3712.     endm
  3713.  
  3714. ;*** ?InvPrg - Concatenates, invokes and purges a macro
  3715. ;
  3716.  
  3717. ?InvPrg macro    name1,name2
  3718.       name1&name2
  3719.       purge name1&name2
  3720.     endm
  3721.  
  3722. ;*** ?Purge - Concatenates and purges a macro
  3723. ;
  3724.  
  3725. ?Purge    macro    name1,name2
  3726.       purge name1&name2
  3727.     endm
  3728.