]> 4ch.mooo.com Git - 16.git/blob - src/lib/modex/demos/c/c_utils.asm
c_utils.asm compiles in watcom but i do not know if it works...
[16.git] / src / lib / modex / demos / c / c_utils.asm
1 ;=======================================================\r
2 ;===  C_UTILS.ASM  - Asm Utilities for C/C++         ===\r
3 ;=======================================================\r
4 \r
5         PAGE    255, 132\r
6 \r
7         .MODEL Huge\r
8 ;       .286\r
9 \r
10         ; ==== MACROS ====\r
11 \r
12         ; macros to PUSH and POP multiple registers\r
13 \r
14 ; PUSHx MACRO R1, R2, R3, R4;, R5, R6, R7, R8\r
15 ;       IFNB <R1>\r
16 ;               push    R1                              ; Save R1\r
17 ;               PUSHx   R2, R3, R4;, R5, R6, R7, R8\r
18 ;       ENDIF\r
19 ; ENDM\r
20 ;\r
21 ; POPx MACRO R1, R2, R3, R4;, R5, R6, R7, R8\r
22 ;       IFNB <R1>\r
23 ;               pop             R1                              ; Restore R1\r
24 ;               POPx    R2, R3, R4;, R5, R6, R7, R8\r
25 ;       ENDIF\r
26 ; ENDM\r
27 \r
28         ; Macro to Clear a Register to 0\r
29 \r
30 CLR MACRO Register\r
31         xor             Register, Register              ; Set Register = 0\r
32 ENDM\r
33 \r
34         ; Macros to Decrement Counter & Jump on Condition\r
35 \r
36 LOOPx MACRO Register, Destination\r
37         dec             Register                                ; Counter--\r
38         jnz             Destination                             ; Jump if not 0\r
39 ENDM\r
40 \r
41 LOOPjz MACRO Register, Destination\r
42         dec             Register                                ; Counter--\r
43         jz              Destination                             ; Jump if 0\r
44 ENDM\r
45 \r
46 \r
47         ; ==== General Constants ====\r
48 \r
49         False   EQU     0\r
50         True    EQU     -1\r
51         nil             EQU 0\r
52 \r
53         b               EQU     BYTE PTR\r
54         w               EQU     WORD PTR\r
55         d               EQU     DWORD PTR\r
56         o               EQU     OFFSET\r
57         f               EQU FAR PTR\r
58         s               EQU     SHORT\r
59         ?x4             EQU <?,?,?,?>\r
60         ?x3             EQU <?,?,?>\r
61 \r
62 \r
63         .Data\r
64 \r
65         EVEN\r
66 \r
67 RND_Seed        DW      7397, 29447, 802\r
68 RND_Mult        DW      179, 183, 182\r
69 RND_ModV        DW      32771, 32779, 32783\r
70 \r
71 CR_LF           DB      13, 10                  ; the CRLF data\r
72 \r
73         .Code\r
74 \r
75 ;===========================================\r
76 ;void far pascal dos_print  (far char *Text)\r
77 ;===========================================\r
78 ;\r
79 ; - Print Text Directly to DOS console w/ CR/LF\r
80 ;\r
81 \r
82         PUBLIC  DOS_PRINT\r
83 \r
84 DP_Stack        STRUC\r
85                                 DW      ?x2     ; DI, SI, DS, BP\r
86                                 DD      ?       ; Caller\r
87         DP_Text         DD      ?       ; Far Address of Text to print\r
88 DP_Stack        ENDS\r
89 \r
90 \r
91 DOS_PRINT        PROC    FAR\r
92 \r
93         ;PUSHx  BP, DS, SI, DI          ; Preserve Important Registers\r
94         push bp\r
95         push ds\r
96         push si\r
97         push di\r
98         mov             BP, SP                          ; Set up Stack Frame\r
99 \r
100         lds     DX, [BP].DP_Text        ; Get Addr of Text$ descriptor\r
101 \r
102         ; Compute Length of string\r
103 \r
104         CLR             CX                                      ; Length = 0\r
105         mov             SI, DX                          ; DS:SI = String data\r
106 \r
107 @@DP_Scan_it:\r
108 \r
109         cmp             b [SI], 0                       ; Null Byte found?\r
110         je              @@DP_Got_Len            ; exit loop if so\r
111 \r
112         inc             CX                                      ; Len++\r
113         inc             SI                                      ; Point to next char\r
114         jmp             s @@DP_Scan_it          ; check again...\r
115 \r
116 @@DP_Got_len:\r
117 \r
118         jcxz    @No_Print                       ; Don't Print if empty\r
119 \r
120         mov             BX, 1                           ; 1= DOS Handle for Display\r
121         mov             AH, 40h                         ; Write Text Function\r
122         int             21h                                     ; Call DOS to do it\r
123 \r
124 @No_Print:\r
125         mov             AX, SEG DGROUP          ; Restore DGroup\r
126         mov             DS, AX\r
127 \r
128         mov             DX, o CR_LF                     ; Get Addr of CR/LF pair\r
129         mov             CX, 2                           ; 2 Characters to Write\r
130         mov             BX, 1                           ; 1= DOS Handle for Display\r
131 \r
132         mov             AH, 40h                         ; Write Text Function\r
133         int             21h                                     ; Call DOS to do it\r
134 \r
135         cld                                                     ; Reset Direction Flag\r
136         ;POPx   DI, SI, DS, BP          ; Restore Saved Registers\r
137         pop di\r
138         pop si\r
139         pop ds\r
140         pop bp\r
141         ret             4                                       ; Exit & Clean Up Stack\r
142 \r
143 DOS_PRINT        ENDP\r
144 \r
145 \r
146 ;===========================================\r
147 ;void far pascal dos_prints (char far *Text)\r
148 ;===========================================\r
149 ;\r
150 ; Print Text Directly to DOS console\r
151 ; without a trailing CR/LF\r
152 ;\r
153 \r
154         PUBLIC  DOS_PRINTS\r
155 \r
156 DOS_PRINTS       PROC    FAR\r
157 \r
158         ;PUSHx  BP, DS, SI, DI          ; Preserve Important Registers\r
159         push bp\r
160         push ds\r
161         push si\r
162         push di\r
163         mov             BP, SP                          ; Set up Stack Frame\r
164 \r
165         lds     DX, [BP].DP_Text        ; Get Addr of Text$ descriptor\r
166 \r
167         ; Compute Length of string\r
168 \r
169         CLR             CX                                      ; Length = 0\r
170         mov             SI, DX                          ; DS:SI = String data\r
171 \r
172 @@DPS_Scan_it:\r
173 \r
174         cmp             b [SI], 0                       ; Null Byte found?\r
175         je              @@DPS_Got_Len           ; exit loop if so\r
176 \r
177         inc             CX                                      ; Len++\r
178         inc             SI                                      ; Point to next char\r
179         jmp             s @@DPS_Scan_it         ; check again...\r
180 \r
181 @@DPS_Got_len:\r
182 \r
183         jcxz    @DPS_Exit                       ; Don't Print if empty\r
184 \r
185         mov             BX, 1                           ; 1= DOS Handle for Display\r
186         mov             AH, 40h                         ; Write Text Function\r
187         int             21h                                     ; Call DOS to do it\r
188 \r
189 @DPS_Exit:\r
190         cld                                                     ; Reset Direction Flag\r
191         ;POPx   DI, SI, DS, BP          ; Restore Saved Registers\r
192         pop di\r
193         pop si\r
194         pop ds\r
195         pop bp\r
196         ret             2                                       ; Exit & Clean Up Stack\r
197 \r
198 DOS_PRINTS       ENDP\r
199 \r
200 \r
201 ;=========================================\r
202 ;void far pascal set_video_mode (int Mode)\r
203 ;=========================================\r
204 ;\r
205 ; Sets the Video Mode through the BIOS\r
206 ;\r
207 \r
208         PUBLIC  SET_VIDEO_MODE\r
209 \r
210 SVM_Stack       STRUC\r
211                                 DW      ?x2     ; DI, SI, DS, BP\r
212                                 DD      ?       ; Caller\r
213         SVM_Mode        DB      ?,? ; Desired Video Mode\r
214 SVM_Stack       ENDS\r
215 \r
216 \r
217 SET_VIDEO_MODE  PROC    FAR\r
218 \r
219         ;PUSHx  BP, DS, SI, DI          ; Preserve Important Registers\r
220         push bp\r
221         push ds\r
222         push si\r
223         push di\r
224         mov             BP, SP                          ; Set up Stack Frame\r
225 \r
226         CLR             AH                                      ; Function 0\r
227         mov             AL, [BP].SVM_Mode       ; Get Mode #\r
228 \r
229         int             10H                                     ; Change Video Modes\r
230 \r
231 @SVM_Exit:\r
232         ;POPx   DI, SI, DS, BP          ; Restore Saved Registers\r
233         pop di\r
234         pop si\r
235         pop ds\r
236         pop bp\r
237         ret             2                                       ; Exit & Clean Up Stack\r
238 \r
239 SET_VIDEO_MODE  ENDP\r
240 \r
241 \r
242 ;===================================\r
243 ;int far pascal scan_keyboard (void)\r
244 ;===================================\r
245 ;\r
246 ; Function to scan keyboard for a pressed key\r
247 ;\r
248 \r
249         PUBLIC  SCAN_KEYBOARD\r
250 \r
251 SCAN_KEYBOARD   PROC    FAR\r
252 \r
253         ;PUSHx  BP, DS, SI, DI          ; Preserve Important Registers\r
254         push bp\r
255         push ds\r
256         push si\r
257         push di\r
258 \r
259         mov             AH, 01H                         ; Function #1\r
260         INT             16H                                     ; Call Keyboard Driver\r
261         JZ              @SK_NO_KEY                      ; Exit if Zero flag set\r
262 \r
263         mov             AH,     00H                             ; Remove Key from Buffer\r
264         INT             16H                                     ; Get Keycode in AX\r
265 \r
266         OR              AL, AL                          ; Low Byte Set (Ascii?)\r
267         JZ              @SK_Exit                        ; if not, it's a F-Key\r
268 \r
269         CLR             AH                                      ; Clear ScanCode if Ascii\r
270         JMP             s @SK_Exit                      ; Return Key in AX\r
271 \r
272 @SK_NO_KEY:\r
273         CLR             AX                                      ; Return Nil (no Keypress)\r
274 \r
275 @SK_Exit:\r
276         cld                                                     ; Reset Direction Flag\r
277         ;POPx   DI, SI, DS, BP          ; Restore Saved Registers\r
278         pop di\r
279         pop si\r
280         pop ds\r
281         pop bp\r
282         ret                                                     ; Exit & Clean Up Stack\r
283 \r
284 SCAN_KEYBOARD   ENDP\r
285 \r
286 \r
287 ;========================================\r
288 ;int far pascal random_int (int MaxValue)\r
289 ;========================================\r
290 ;\r
291 ; Returns a pseudo-random number in the range of (0.. MaxInt-1)\r
292 ;\r
293 \r
294 \r
295         PUBLIC  RANDOM_INT\r
296 \r
297 RI_Stack        STRUC\r
298                                 DW      ?       ; BP\r
299                                 DD      ?       ; Caller\r
300         RI_MaxVal       DW      ?       ; Maximum Value to Return + 1\r
301 RI_Stack        ENDS\r
302 \r
303 \r
304 RANDOM_INT      PROC    FAR\r
305 \r
306         push    BP                                      ; Preserve Important Registers\r
307         mov             BP, SP                          ; Set up Stack Frame\r
308 \r
309         CLR             BX                                      ; BX is the data index\r
310         CLR             CX                              ; CX is the accumulator\r
311 \r
312 REPT 3\r
313         mov             AX, RND_Seed[BX]        ; load the initial seed\r
314         mul             RND_Mult[BX]            ; multiply it\r
315         div             RND_ModV[BX]            ; and obtain the Mod value\r
316         mov             RND_Seed[BX], DX        ; save that for the next time\r
317 \r
318         add             CX, DX                          ; add it into the accumulator\r
319         inc             BX\r
320         inc             BX                      ; point to the next set of values\r
321 ENDM\r
322 \r
323         mov             AX, CX                          ; AX = Random #\r
324         CLR             DX                                      ; DX = 0\r
325         div             [BP].RI_MaxVal          ; DX = DX:AX / MAxVal Remainder\r
326 \r
327         mov             AX, DX\r
328 \r
329         pop             BP                                      ; Restore BP\r
330         ret             2                               ; back to BASIC with AX holding the result\r
331 \r
332 RANDOM_INT      ENDP\r
333 \r
334 \r
335 ;==================================\r
336 ;void far pascal init_random (void)\r
337 ;==================================\r
338 ;\r
339 ; Scrambles the psuedo-random number sequence\r
340 ; (XOR's the seed value with the timer)\r
341 ;\r
342 \r
343         PUBLIC  INIT_RANDOM\r
344 \r
345 INIT_RANDOM     PROC    FAR\r
346 \r
347         CLR             AX                                      ; Segment = 0000\r
348         mov             ES, AX\r
349         mov             AX, ES:[046Ch]      ; Get Timer Lo Word\r
350 \r
351         xor             RND_Seed, AX            ; Scramble 1st Seed\r
352 \r
353         ret                                                     ; Exit & Clean Up Stack\r
354 \r
355 INIT_RANDOM     ENDP\r
356 \r
357 ;=========================================\r
358 ;int far pascal int_sqr (int X, int Round)\r
359 ;=========================================\r
360 ;\r
361 ; Returns the Integer Square Root of (X)\r
362 ; Round allows the return value to be rounded to the\r
363 ; nearest integer value by passing 0x80.  Passing 0\r
364 ; return the Integer Portion only.  The rounding amound is\r
365 ; a number from 0 to 1 multiplied by 256, thus\r
366 ; 0.5 * 0x100 = 0x80!\r
367 ;\r
368 \r
369 ISQ_Stack       STRUC\r
370                                         DW      ?,?     ; BP, DI\r
371                                         DD      ?       ; Caller\r
372         ISQ_Round               DW      ?       ; Amount to Round Result * 256\r
373         ISQ_X                   DW      ?       ; "X"\r
374 ISQ_Stack       ENDS\r
375 \r
376         PUBLIC  INT_SQR\r
377 \r
378 INT_SQR         PROC    FAR\r
379 \r
380     ;PUSHx   BP, DI                             ; Save BP\r
381         push bp\r
382         push di\r
383     mov     BP, SP                              ; Set up Stack Frame\r
384 \r
385         xor     AX, AX                          ; {xor eax,eax}\r
386         xor     DX, DX                          ; {xor edx,edx}\r
387         mov     DI, [BP].ISQ_X          ; {mov edi,x}\r
388 \r
389         mov     CX, 16                          ; {mov cx, 32}\r
390 \r
391 @ISQ_L:\r
392 \r
393         shl     DI, 1                           ; {shl edi,1}\r
394         rcl     DX, 1                           ; {rcl edx,1}\r
395         shl     DI, 1                           ; {shl edi,1}\r
396         rcl     DX, 1                           ; {rcl edx,1}\r
397         shl     AX, 1                           ; {shl eax,1}\r
398         mov     BX, AX                          ; {mov ebx,eax}\r
399         shl     BX, 1                           ; {shl ebx,1}\r
400         inc     BX                                      ; {inc ebx}\r
401         cmp     DX, BX                          ; {cmp edx,ebx}\r
402         jl              @ISQ_S\r
403 \r
404         sub     DX, BX                          ; {sub edx,ebx}\r
405         inc     AX                                      ; {inc eax}\r
406 \r
407 @ISQ_S:\r
408         loop    @ISQ_L\r
409 \r
410         add     ax, [BP].ISQ_Round      ; {add eax,$00008000}\r
411                                                                 ; {*round* result in hi word: ie. +0.5}\r
412         shr     ax, 1                           ; {shr eax,16}  {to ax (result)}\r
413         shr     ax, 1                           ; {shr eax,16}  {to ax (result)}\r
414         shr     ax, 1                           ; {shr eax,16}  {to ax (result)}\r
415         shr     ax, 1                           ; {shr eax,16}  {to ax (result)}\r
416         shr     ax, 1                           ; {shr eax,16}  {to ax (result)}\r
417         shr     ax, 1                           ; {shr eax,16}  {to ax (result)}\r
418         shr     ax, 1                           ; {shr eax,16}  {to ax (result)}\r
419         shr     ax, 1                           ; {shr eax,16}  {to ax (result)}\r
420 \r
421         ;POPx   DI, BP                          ; Restore Registers\r
422         pop di\r
423         pop bp\r
424         ret             4                                       ; Exit\r
425 \r
426 INT_SQR         ENDP\r
427 \r
428 ;=================================\r
429 ;int far pascal timer_count (void)\r
430 ;=================================\r
431 ;\r
432 ; Returns the current timer value as an integer/long integer\r
433 ;\r
434 \r
435         PUBLIC  TIMER_COUNT\r
436 \r
437 TIMER_COUNT      PROC    FAR\r
438 \r
439         CLR             AX                                      ; Segment = 0000\r
440         mov             ES, AX\r
441         mov             AX, ES:[046Ch]      ; Get Timer Lo Word\r
442         mov             DX, ES:[046Eh]          ; Get Timer Hi Word\r
443         ret                                                     ; Exit & Clean Up Stack\r
444 \r
445 TIMER_COUNT      ENDP\r
446 \r
447 \r
448         END\r