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