home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / warptlk3.zip / TOOLKIT / INC / BASEMACA.INC < prev    next >
Text File  |  1995-08-24  |  115KB  |  3,567 lines

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