1 ;=======================================================
\r
2 ;=== C_UTILS.ASM - Asm Utilities for C/C++ ===
\r
3 ;=======================================================
\r
12 ; macros to PUSH and POP multiple registers
\r
14 ; PUSHx MACRO R1, R2, R3, R4;, R5, R6, R7, R8
\r
17 ; PUSHx R2, R3, R4;, R5, R6, R7, R8
\r
21 ; POPx MACRO R1, R2, R3, R4;, R5, R6, R7, R8
\r
23 ; pop R1 ; Restore R1
\r
24 ; POPx R2, R3, R4;, R5, R6, R7, R8
\r
28 ; Macro to Clear a Register to 0
\r
31 xor Register, Register ; Set Register = 0
\r
34 ; Macros to Decrement Counter & Jump on Condition
\r
36 LOOPx MACRO Register, Destination
\r
37 dec Register ; Counter--
\r
38 jnz Destination ; Jump if not 0
\r
41 LOOPjz MACRO Register, Destination
\r
42 dec Register ; Counter--
\r
43 jz Destination ; Jump if 0
\r
47 ; ==== General Constants ====
\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
73 CR_LF DB 13, 10 ; the CRLF data
\r
77 ;===========================================
\r
78 ;void far pascal dos_print (far char *Text)
\r
79 ;===========================================
\r
81 ; - Print Text Directly to DOS console w/ CR/LF
\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
92 DP_Text DD ? ; Far Address of Text to print
\r
98 ;PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
103 mov BP, SP ; Set up Stack Frame
\r
105 lds DX, [BP].DP_Text ; Get Addr of Text$ descriptor
\r
107 ; Compute Length of string
\r
109 CLR CX ; Length = 0
\r
110 mov SI, DX ; DS:SI = String data
\r
114 cmp b [SI], 0 ; Null Byte found?
\r
115 je @@DP_Got_Len ; exit loop if so
\r
118 inc SI ; Point to next char
\r
119 jmp s @@DP_Scan_it ; check again...
\r
123 jcxz @No_Print ; Don't Print if empty
\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
130 mov AX, SEG DGROUP ; Restore DGroup
\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
137 mov AH, 40h ; Write Text Function
\r
138 int 21h ; Call DOS to do it
\r
140 cld ; Reset Direction Flag
\r
141 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
146 ret 4 ; Exit & Clean Up Stack
\r
151 ;===========================================
\r
152 ;void far pascal dos_prints (char far *Text)
\r
153 ;===========================================
\r
155 ; Print Text Directly to DOS console
\r
156 ; without a trailing CR/LF
\r
161 DOS_PRINTS PROC FAR
\r
163 ;PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
168 mov BP, SP ; Set up Stack Frame
\r
170 lds DX, [BP].DP_Text ; Get Addr of Text$ descriptor
\r
172 ; Compute Length of string
\r
174 CLR CX ; Length = 0
\r
175 mov SI, DX ; DS:SI = String data
\r
179 cmp b [SI], 0 ; Null Byte found?
\r
180 je @@DPS_Got_Len ; exit loop if so
\r
183 inc SI ; Point to next char
\r
184 jmp s @@DPS_Scan_it ; check again...
\r
188 jcxz @DPS_Exit ; Don't Print if empty
\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
195 cld ; Reset Direction Flag
\r
196 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
201 ret 2 ; Exit & Clean Up Stack
\r
206 ;=========================================
\r
207 ;void far pascal set_video_mode (int Mode)
\r
208 ;=========================================
\r
210 ; Sets the Video Mode through the BIOS
\r
213 PUBLIC SET_VIDEO_MODE
\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
221 SVM_Mode DB ?,? ; Desired Video Mode
\r
225 SET_VIDEO_MODE PROC FAR
\r
227 ;PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
232 mov BP, SP ; Set up Stack Frame
\r
234 CLR AH ; Function 0
\r
235 mov AL, [BP].SVM_Mode ; Get Mode #
\r
237 int 10H ; Change Video Modes
\r
240 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
245 ret 2 ; Exit & Clean Up Stack
\r
247 SET_VIDEO_MODE ENDP
\r
250 ;===================================
\r
251 ;int far pascal scan_keyboard (void)
\r
252 ;===================================
\r
254 ; Function to scan keyboard for a pressed key
\r
257 PUBLIC SCAN_KEYBOARD
\r
259 SCAN_KEYBOARD PROC FAR
\r
261 ;PUSHx BP, DS, SI, DI ; Preserve Important Registers
\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
271 mov AH, 00H ; Remove Key from Buffer
\r
272 INT 16H ; Get Keycode in AX
\r
274 OR AL, AL ; Low Byte Set (Ascii?)
\r
275 JZ @SK_Exit ; if not, it's a F-Key
\r
277 CLR AH ; Clear ScanCode if Ascii
\r
278 JMP s @SK_Exit ; Return Key in AX
\r
281 CLR AX ; Return Nil (no Keypress)
\r
284 cld ; Reset Direction Flag
\r
285 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
290 ret ; Exit & Clean Up Stack
\r
295 ;========================================
\r
296 ;int far pascal random_int (int MaxValue)
\r
297 ;========================================
\r
299 ; Returns a pseudo-random number in the range of (0.. MaxInt-1)
\r
308 RI_MaxVal DW ? ; Maximum Value to Return + 1
\r
312 RANDOM_INT PROC FAR
\r
314 push BP ; Preserve Important Registers
\r
315 mov BP, SP ; Set up Stack Frame
\r
317 CLR BX ; BX is the data index
\r
318 CLR CX ; CX is the accumulator
\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
326 add CX, DX ; add it into the accumulator
\r
328 inc BX ; point to the next set of values
\r
331 mov AX, CX ; AX = Random #
\r
333 div [BP].RI_MaxVal ; DX = DX:AX / MAxVal Remainder
\r
337 pop BP ; Restore BP
\r
338 ret 2 ; back to BASIC with AX holding the result
\r
343 ;==================================
\r
344 ;void far pascal init_random (void)
\r
345 ;==================================
\r
347 ; Scrambles the psuedo-random number sequence
\r
348 ; (XOR's the seed value with the timer)
\r
353 INIT_RANDOM PROC FAR
\r
355 CLR AX ; Segment = 0000
\r
357 mov AX, ES:[046Ch] ; Get Timer Lo Word
\r
359 xor RND_Seed, AX ; Scramble 1st Seed
\r
361 ret ; Exit & Clean Up Stack
\r
365 ;=========================================
\r
366 ;int far pascal int_sqr (int X, int Round)
\r
367 ;=========================================
\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
380 ISQ_Round DW ? ; Amount to Round Result * 256
\r
388 ;PUSHx BP, DI ; Save BP
\r
391 mov BP, SP ; Set up Stack Frame
\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
397 mov CX, 16 ; {mov cx, 32}
\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
409 cmp DX, BX ; {cmp edx,ebx}
\r
412 sub DX, BX ; {sub edx,ebx}
\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
429 ;POPx DI, BP ; Restore Registers
\r
436 ;=================================
\r
437 ;int far pascal timer_count (void)
\r
438 ;=================================
\r
440 ; Returns the current timer value as an integer/long integer
\r
445 TIMER_COUNT PROC FAR
\r
447 CLR AX ; Segment = 0000
\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