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