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
67 RND_Seed DW 7397, 29447, 802
\r
68 RND_Mult DW 179, 183, 182
\r
69 RND_ModV DW 32771, 32779, 32783
\r
71 CR_LF DB 13, 10 ; the CRLF data
\r
75 ;===========================================
\r
76 ;void far pascal dos_print (far char *Text)
\r
77 ;===========================================
\r
79 ; - Print Text Directly to DOS console w/ CR/LF
\r
85 DW ?x2 ; DI, SI, DS, BP
\r
87 DP_Text DD ? ; Far Address of Text to print
\r
93 ;PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
98 mov BP, SP ; Set up Stack Frame
\r
100 lds DX, [BP].DP_Text ; Get Addr of Text$ descriptor
\r
102 ; Compute Length of string
\r
104 CLR CX ; Length = 0
\r
105 mov SI, DX ; DS:SI = String data
\r
109 cmp b [SI], 0 ; Null Byte found?
\r
110 je @@DP_Got_Len ; exit loop if so
\r
113 inc SI ; Point to next char
\r
114 jmp s @@DP_Scan_it ; check again...
\r
118 jcxz @No_Print ; Don't Print if empty
\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
125 mov AX, SEG DGROUP ; Restore DGroup
\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
132 mov AH, 40h ; Write Text Function
\r
133 int 21h ; Call DOS to do it
\r
135 cld ; Reset Direction Flag
\r
136 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
141 ret 4 ; Exit & Clean Up Stack
\r
146 ;===========================================
\r
147 ;void far pascal dos_prints (char far *Text)
\r
148 ;===========================================
\r
150 ; Print Text Directly to DOS console
\r
151 ; without a trailing CR/LF
\r
156 DOS_PRINTS PROC FAR
\r
158 ;PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
163 mov BP, SP ; Set up Stack Frame
\r
165 lds DX, [BP].DP_Text ; Get Addr of Text$ descriptor
\r
167 ; Compute Length of string
\r
169 CLR CX ; Length = 0
\r
170 mov SI, DX ; DS:SI = String data
\r
174 cmp b [SI], 0 ; Null Byte found?
\r
175 je @@DPS_Got_Len ; exit loop if so
\r
178 inc SI ; Point to next char
\r
179 jmp s @@DPS_Scan_it ; check again...
\r
183 jcxz @DPS_Exit ; Don't Print if empty
\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
190 cld ; Reset Direction Flag
\r
191 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
196 ret 2 ; Exit & Clean Up Stack
\r
201 ;=========================================
\r
202 ;void far pascal set_video_mode (int Mode)
\r
203 ;=========================================
\r
205 ; Sets the Video Mode through the BIOS
\r
208 PUBLIC SET_VIDEO_MODE
\r
211 DW ?x2 ; DI, SI, DS, BP
\r
213 SVM_Mode DB ?,? ; Desired Video Mode
\r
217 SET_VIDEO_MODE PROC FAR
\r
219 ;PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
224 mov BP, SP ; Set up Stack Frame
\r
226 CLR AH ; Function 0
\r
227 mov AL, [BP].SVM_Mode ; Get Mode #
\r
229 int 10H ; Change Video Modes
\r
232 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
237 ret 2 ; Exit & Clean Up Stack
\r
239 SET_VIDEO_MODE ENDP
\r
242 ;===================================
\r
243 ;int far pascal scan_keyboard (void)
\r
244 ;===================================
\r
246 ; Function to scan keyboard for a pressed key
\r
249 PUBLIC SCAN_KEYBOARD
\r
251 SCAN_KEYBOARD PROC FAR
\r
253 ;PUSHx BP, DS, SI, DI ; Preserve Important Registers
\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
263 mov AH, 00H ; Remove Key from Buffer
\r
264 INT 16H ; Get Keycode in AX
\r
266 OR AL, AL ; Low Byte Set (Ascii?)
\r
267 JZ @SK_Exit ; if not, it's a F-Key
\r
269 CLR AH ; Clear ScanCode if Ascii
\r
270 JMP s @SK_Exit ; Return Key in AX
\r
273 CLR AX ; Return Nil (no Keypress)
\r
276 cld ; Reset Direction Flag
\r
277 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
282 ret ; Exit & Clean Up Stack
\r
287 ;========================================
\r
288 ;int far pascal random_int (int MaxValue)
\r
289 ;========================================
\r
291 ; Returns a pseudo-random number in the range of (0.. MaxInt-1)
\r
300 RI_MaxVal DW ? ; Maximum Value to Return + 1
\r
304 RANDOM_INT PROC FAR
\r
306 push BP ; Preserve Important Registers
\r
307 mov BP, SP ; Set up Stack Frame
\r
309 CLR BX ; BX is the data index
\r
310 CLR CX ; CX is the accumulator
\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
318 add CX, DX ; add it into the accumulator
\r
320 inc BX ; point to the next set of values
\r
323 mov AX, CX ; AX = Random #
\r
325 div [BP].RI_MaxVal ; DX = DX:AX / MAxVal Remainder
\r
329 pop BP ; Restore BP
\r
330 ret 2 ; back to BASIC with AX holding the result
\r
335 ;==================================
\r
336 ;void far pascal init_random (void)
\r
337 ;==================================
\r
339 ; Scrambles the psuedo-random number sequence
\r
340 ; (XOR's the seed value with the timer)
\r
345 INIT_RANDOM PROC FAR
\r
347 CLR AX ; Segment = 0000
\r
349 mov AX, ES:[046Ch] ; Get Timer Lo Word
\r
351 xor RND_Seed, AX ; Scramble 1st Seed
\r
353 ret ; Exit & Clean Up Stack
\r
357 ;=========================================
\r
358 ;int far pascal int_sqr (int X, int Round)
\r
359 ;=========================================
\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
372 ISQ_Round DW ? ; Amount to Round Result * 256
\r
380 ;PUSHx BP, DI ; Save BP
\r
383 mov BP, SP ; Set up Stack Frame
\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
389 mov CX, 16 ; {mov cx, 32}
\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
401 cmp DX, BX ; {cmp edx,ebx}
\r
404 sub DX, BX ; {sub edx,ebx}
\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
421 ;POPx DI, BP ; Restore Registers
\r
428 ;=================================
\r
429 ;int far pascal timer_count (void)
\r
430 ;=================================
\r
432 ; Returns the current timer value as an integer/long integer
\r
437 TIMER_COUNT PROC FAR
\r
439 CLR AX ; Segment = 0000
\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