enable -nofade
[btb/d2x.git] / include / psmacros.inc
1 ; THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
2 ; SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
3 ; END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
4 ; ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
5 ; IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
6 ; SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
7 ; FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
8 ; CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
9 ; AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
10 ; COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
11 ;Shortcuts for casting
12
13 w equ word ptr
14 b equ byte ptr
15
16
17 ;The macros @ArgCount() & @ArgRev() are from the file MACROS.INC, provided 
18 ;with MASM.  I have included them here because MACROS.INC has bugs, so I 
19 ;couldn't just include it.
20
21 ; Utility Macros - Version 1.0 - for Microsoft Macro Assembler 6.0
22 ; (C) Copyright Microsoft Corporation, 1987,1988,1989,1990
23
24 ;* @ArgCount - Macro function returns the number of arguments in a
25 ;* VARARG list.
26 ;*
27 ;* Params:  arglist - arguments to be counted
28
29 @ArgCount MACRO arglist:VARARG
30     LOCAL count
31     count = 0
32     FOR arg, <arglist>
33         count = count + 1
34     ENDM
35     EXITM %count
36 ENDM
37
38 ;* @ArgRev - Macro function returns a reversed order version of a
39 ;* VARARG list.
40 ;*
41 ;* Shows:   Operators           - <>         !        %
42 ;*          String directive    - SUBSTR
43 ;*          Predefined function - @SizeStr
44 ;*
45 ;* Params:  arglist - arguments to be reversed
46
47 @ArgRev MACRO arglist:vararg
48     LOCAL txt, arg
49     txt TEXTEQU <>
50 %   FOR arg, <arglist>
51         txt CATSTR <arg>, <!,>, txt
52     ENDM
53
54     txt SUBSTR  txt, 1, @SizeStr( %txt ) - 1
55     txt CATSTR  <!<>, txt, <!>>
56     EXITM txt
57 ENDM
58
59 ;These macros are used for decalaring external vars and functions
60
61 ;this macro is used to declare several symbols of the same type
62 ;usage is:  extdef  type,sym0,sym1,...
63 extdef  macro   type,syms:vararg
64         for     sym,<syms>
65          externdef sym:type
66         endm
67         endm
68
69 ;this macro is used to generate ext<type> macros 
70 extgen  macro   type,id
71 ext&id  macro   syms:vararg
72         extdef  type,syms
73         endm
74         endm
75
76 ;macros for common types, such as word (extw), byte (extb), & near (extn)
77
78         extgen  word,w
79         extgen  byte,b
80         extgen  dword,d
81         extgen  near,n
82
83
84 ;compute the absolute value of eax.  afterwards, edx=sign (0 or -1)
85 abs_eax macro
86         cdq
87         xor     eax,edx
88         sub     eax,edx
89         endm
90
91 ;PUSHM & POPM are used for multiple registers.  Note that POPM pops in the
92 ;reverse order from PUSHM, so the list of regs shouls be the same for both.
93 ;You can also define a constant which is a register list, and use it as the
94 ;argument to both macros.
95
96 ;push multiple registers
97 pushm   macro   args:vararg
98         local   arg
99         for     arg,<args>
100          push   arg
101         endm
102         endm
103
104 ;pop multiple registers
105 popm    macro   args:vararg
106         local   arg
107 %       for     arg,@ArgRev(args)
108          pop    arg
109         endm
110         endm
111
112 ;PUSHLONG pushes a long, zero extending the argument if necessary
113 ;it trashes no registers
114 pushlong        macro   arg
115         local   s
116 s = TYPE arg
117         if      s EQ 0  ;constant, I think
118          push   arg
119         elseif  s LT 4
120          push   eax
121          movzx  eax,arg
122          xchg   eax,[esp]
123         else
124          push   arg
125         endif
126
127         endm
128
129 ;PUSHML is pushm using pushlong
130 pushml  macro   args:vararg
131         local   arg
132         for     arg,<args>
133          pushlong       arg
134         endm
135         endm
136
137
138 ;DBSTR stores a string with occurances of \n converted to newlines
139 ;this macro expects quotes around the string
140 ;
141 ;note the 'fudge' variable.  This fixes an odd problem with the way
142 ;the string macros deal with backslashes - @InStr() treats them like
143 ;any other character, but @SubStr() ignores them
144 dbstr   macro   str
145         local   pos,oldpos,len,fudge
146
147         oldpos = 2      ;skip initial quote
148         fudge = 0
149         len = @SizeStr(str)
150
151         pos = @InStr(oldpos,str,<\n>)
152
153         while   pos GE oldpos
154
155          if     pos GT oldpos
156           %db   '&@SubStr(<&str>,&oldpos-&fudge,&pos-&oldpos)'
157          endif
158          db     10
159          oldpos = pos+2
160          fudge = fudge+1
161
162          pos = @InStr(oldpos,<str>,<\n>)
163
164         endm
165
166         if      oldpos LT len
167 ;;;      %db    '&@SubStr(&str,&oldpos-&fudge,&len-&oldpos-1)'
168          %db    '&@SubStr(&str,&oldpos-&fudge,&len-&oldpos)'
169         endif
170
171         endm
172
173
174 ;MPRINTF is a macro interface to the mprintf funcion.  It puts the format
175 ;string in the code segment at the current location, pushes the args, and
176 ;calls mprintf. If window is not specified, zero is assumed
177 mprintf macro   window:=<0>,format:req,args:vararg
178         local   string,skip
179         ifndef  NDEBUG
180         ifndef  NMONO
181         extn    mprintf_
182         jmp     skip
183 string  label   byte
184         dbstr   format
185         db      0
186 skip:
187         ifnb    <args>
188 %        pushml @ArgRev(args)
189         endif
190         pushml  offset string,window
191         call    mprintf_
192         add     esp,(@ArgCount(args)+2)*4       ;fix stack
193         endif
194         endif
195         endm
196
197
198 ;MPRINTF_AT - version of mprintf with coordinates
199 mprintf_at      macro   window:=<0>,row,col,format:req,args:vararg
200         local   string,skip
201         ifndef  NDEBUG
202         ifndef  NMONO
203         extn    mprintf_at_
204         jmp     skip
205 string  label   byte
206         dbstr   format
207         db      0
208 skip:
209         ifnb    <args>
210 %        pushml @ArgRev(args)
211         endif
212         pushml  offset string,col,row,window
213         call    mprintf_at_
214         add     esp,(@ArgCount(args)+4)*4       ;fix stack
215         endif
216         endif
217         endm
218
219
220 ;DEBUG calls mprintf with window 0, preserving all registers and flags
221 ;is is conditionall assembled based on the DEBUG_ON flags
222 debug   macro   format:req,args:vararg
223         ifndef  NDEBUG
224          pushf          ;save flags
225          push   eax     ;mprintf trashes eax
226          mprintf        ,format,args
227          pop    eax
228          popf
229         endif
230         endm
231
232 ;DEBUG_AT - version of debug with coordinates
233 debug_at        macro   row,col,format:req,args:vararg
234         ifndef  NDEBUG
235          pushf          ;save flags
236          push   eax     ;mprintf trashes eax
237          mprintf_at ,row,col,format,args
238          pop    eax
239          popf
240         endif
241         endm
242
243 ;Debugging breakpoint macros
244
245 ;print a message, and do an int3 to pop into the debugger  
246 debug_brk       macro   str
247         ifndef  NDEBUG
248          debug  str
249          int    3
250         endif
251         endm
252
253 break_if        macro   cc,str
254         local   skip,yes_break
255         ifndef  NDEBUG
256          j&cc   yes_break
257          jmp    skip
258 yes_break:       debug_brk str
259 skip:
260         endif
261         endm
262
263 ;returns the bit number of the highest bit
264 @HighBit        macro   n
265         local   t,c
266         if      n EQ 0
267          exitm  <-1>    ;error!
268         else
269          t = n
270          c = 0
271          while  t GT 1
272           t = t SHR 1
273           c = c+1
274          endm
275          exitm  <c>
276         endif
277         endm
278
279 ;returns the bit number of the lowest bit
280 @LowBit macro   n
281         ;local  t,c
282         local   c
283         if      n EQ 0
284          exitm  <-1>    ;error!
285         else
286          t = n
287          c = 0
288          while  (t and 1) EQ 0
289           t = t SHR 1
290           c = c+1
291          endm
292          exitm  <c>
293         endif
294         endm
295
296
297 ;"multiply" the given register by a constant, using whatever method is
298 ;best for the given constant
299 imulc   macro   reg,c
300         local   low,high
301
302         if      c EQ 0
303          xor    reg,reg
304         elseif  c EQ 1
305         elseif  c EQ 3
306          lea    reg,[reg*2+reg]
307         elseif  c EQ 5
308          lea    reg,[reg*4+reg]
309         elseif  c EQ 6
310          lea    reg,[reg*2+reg] ;*3
311          shl    reg,1   ;*6
312         elseif  c EQ 9
313          lea    reg,[reg*8+reg]
314         elseif  c EQ 36
315          lea    reg,[reg*8+reg]
316          sal    reg,2
317         else
318          low = @LowBit(c)
319          high = @HighBit(c)
320          if     low EQ high
321           shl   reg,@LowBit(c)
322          else
323           imul  reg,c
324           echo  Warning: Using imul, to perform multiply by &c
325           ;; .err
326          endif
327         endif
328
329         endm
330