Microsoft (R) Macro Assembler Version 6.11 07/03/14 12:38:18 c_utils.asm Page 1 - 1 ;======================================================= ;=== C_UTILS.ASM - Asm Utilities for C/C++ === ;======================================================= PAGE 255, 132 .MODEL Medium .286 ; ==== MACROS ==== ; macros to PUSH and POP multiple registers PUSHx MACRO R1, R2, R3, R4, R5, R6, R7, R8 IFNB push R1 ; Save R1 PUSHx R2, R3, R4, R5, R6, R7, R8 ENDIF ENDM POPx MACRO R1, R2, R3, R4, R5, R6, R7, R8 IFNB pop R1 ; Restore R1 POPx R2, R3, R4, R5, R6, R7, R8 ENDIF ENDM ; Macro to Clear a Register to 0 CLR MACRO Register xor Register, Register ; Set Register = 0 ENDM ; Macros to Decrement Counter & Jump on Condition LOOPx MACRO Register, Destination dec Register ; Counter-- jnz Destination ; Jump if not 0 ENDM LOOPjz MACRO Register, Destination dec Register ; Counter-- jz Destination ; Jump if 0 ENDM ; ==== General Constants ==== = 0000 False EQU 0 =-0001 True EQU -1 = 0000 nil EQU 0 = BYTE PTR b EQU BYTE PTR = WORD PTR w EQU WORD PTR = DWORD PTR d EQU DWORD PTR = OFFSET o EQU OFFSET = FAR PTR f EQU FAR PTR = SHORT s EQU SHORT = ?,?,?,? ?x4 EQU = ?,?,? ?x3 EQU 0000 .Data EVEN 0000 1CE5 7307 0322 RND_Seed DW 7397, 29447, 802 0006 00B3 00B7 00B6 RND_Mult DW 179, 183, 182 000C 8003 800B 800F RND_ModV DW 32771, 32779, 32783 0012 0D 0A CR_LF DB 13, 10 ; the CRLF data 0000 .Code ;=========================================== ;void far pascal dos_print (far char *Text) ;=========================================== ; ; - Print Text Directly to DOS console w/ CR/LF ; PUBLIC DOS_PRINT 0010 DP_Stack STRUC 0000 0000 0000 0000 DW ?x4 ; DI, SI, DS, BP 0000 0008 00000000 DD ? ; Caller 000C 00000000 DP_Text DD ? ; Far Address of Text to print DP_Stack ENDS 0000 DOS_PRINT PROC FAR PUSHx BP, DS, SI, DI ; Preserve Important Registers 0000 55 1 push BP ; Save R1 0001 1E 2 push DS ; Save R1 0002 56 3 push SI ; Save R1 0003 57 4 push DI ; Save R1 0004 8B EC mov BP, SP ; Set up Stack Frame 0006 C5 56 0C lds DX, [BP].DP_Text ; Get Addr of Text$ descriptor ; Compute Length of string CLR CX ; Length = 0 0009 33 C9 1 xor CX, CX ; Set Register = 0 000B 8B F2 mov SI, DX ; DS:SI = String data 000D @@DP_Scan_it: 000D 80 3C 00 cmp b [SI], 0 ; Null Byte found? 0010 74 04 je @@DP_Got_Len ; exit loop if so 0012 41 inc CX ; Len++ 0013 46 inc SI ; Point to next char 0014 EB F7 jmp s @@DP_Scan_it ; check again... 0016 @@DP_Got_len: 0016 E3 07 jcxz @No_Print ; Don't Print if empty 0018 BB 0001 mov BX, 1 ; 1= DOS Handle for Display 001B B4 40 mov AH, 40h ; Write Text Function 001D CD 21 int 21h ; Call DOS to do it 001F @No_Print: 001F B8 ---- R mov AX, SEG DGROUP ; Restore DGroup 0022 8E D8 mov DS, AX 0024 BA 0012 R mov DX, o CR_LF ; Get Addr of CR/LF pair 0027 B9 0002 mov CX, 2 ; 2 Characters to Write 002A BB 0001 mov BX, 1 ; 1= DOS Handle for Display 002D B4 40 mov AH, 40h ; Write Text Function 002F CD 21 int 21h ; Call DOS to do it 0031 FC cld ; Reset Direction Flag POPx DI, SI, DS, BP ; Restore Saved Registers 0032 5F 1 pop DI ; Restore R1 0033 5E 2 pop SI ; Restore R1 0034 1F 3 pop DS ; Restore R1 0035 5D 4 pop BP ; Restore R1 0036 CA 0004 ret 4 ; Exit & Clean Up Stack 0039 DOS_PRINT ENDP ;=========================================== ;void far pascal dos_prints (char far *Text) ;=========================================== ; ; Print Text Directly to DOS console ; without a trailing CR/LF ; PUBLIC DOS_PRINTS 0039 DOS_PRINTS PROC FAR PUSHx BP, DS, SI, DI ; Preserve Important Registers 0039 55 1 push BP ; Save R1 003A 1E 2 push DS ; Save R1 003B 56 3 push SI ; Save R1 003C 57 4 push DI ; Save R1 003D 8B EC mov BP, SP ; Set up Stack Frame 003F C5 56 0C lds DX, [BP].DP_Text ; Get Addr of Text$ descriptor ; Compute Length of string CLR CX ; Length = 0 0042 33 C9 1 xor CX, CX ; Set Register = 0 0044 8B F2 mov SI, DX ; DS:SI = String data 0046 @@DPS_Scan_it: 0046 80 3C 00 cmp b [SI], 0 ; Null Byte found? 0049 74 04 je @@DPS_Got_Len ; exit loop if so 004B 41 inc CX ; Len++ 004C 46 inc SI ; Point to next char 004D EB F7 jmp s @@DPS_Scan_it ; check again... 004F @@DPS_Got_len: 004F E3 07 jcxz @DPS_Exit ; Don't Print if empty 0051 BB 0001 mov BX, 1 ; 1= DOS Handle for Display 0054 B4 40 mov AH, 40h ; Write Text Function 0056 CD 21 int 21h ; Call DOS to do it 0058 @DPS_Exit: 0058 FC cld ; Reset Direction Flag POPx DI, SI, DS, BP ; Restore Saved Registers 0059 5F 1 pop DI ; Restore R1 005A 5E 2 pop SI ; Restore R1 005B 1F 3 pop DS ; Restore R1 005C 5D 4 pop BP ; Restore R1 005D CA 0002 ret 2 ; Exit & Clean Up Stack 0060 DOS_PRINTS ENDP ;========================================= ;void far pascal set_video_mode (int Mode) ;========================================= ; ; Sets the Video Mode through the BIOS ; PUBLIC SET_VIDEO_MODE 000E SVM_Stack STRUC 0000 0000 0000 0000 DW ?x4 ; DI, SI, DS, BP 0000 0008 00000000 DD ? ; Caller 000C 00 00 SVM_Mode DB ?,? ; Desired Video Mode SVM_Stack ENDS 0060 SET_VIDEO_MODE PROC FAR PUSHx BP, DS, SI, DI ; Preserve Important Registers 0060 55 1 push BP ; Save R1 0061 1E 2 push DS ; Save R1 0062 56 3 push SI ; Save R1 0063 57 4 push DI ; Save R1 0064 8B EC mov BP, SP ; Set up Stack Frame CLR AH ; Function 0 0066 32 E4 1 xor AH, AH ; Set Register = 0 0068 8A 46 0C mov AL, [BP].SVM_Mode ; Get Mode # 006B CD 10 int 10H ; Change Video Modes 006D @SVM_Exit: POPx DI, SI, DS, BP ; Restore Saved Registers 006D 5F 1 pop DI ; Restore R1 006E 5E 2 pop SI ; Restore R1 006F 1F 3 pop DS ; Restore R1 0070 5D 4 pop BP ; Restore R1 0071 CA 0002 ret 2 ; Exit & Clean Up Stack 0074 SET_VIDEO_MODE ENDP ;=================================== ;int far pascal scan_keyboard (void) ;=================================== ; ; Function to scan keyboard for a pressed key ; PUBLIC SCAN_KEYBOARD 0074 SCAN_KEYBOARD PROC FAR PUSHx BP, DS, SI, DI ; Preserve Important Registers 0074 55 1 push BP ; Save R1 Microsoft (R) Macro Assembler Version 6.11 07/03/14 12:38:18 c_utils.asm Page 2 - 1 0075 1E 2 push DS ; Save R1 0076 56 3 push SI ; Save R1 0077 57 4 push DI ; Save R1 0078 B4 01 mov AH, 01H ; Function #1 007A CD 16 INT 16H ; Call Keyboard Driver 007C 74 0C JZ @SK_NO_KEY ; Exit if Zero flag set 007E B4 00 mov AH, 00H ; Remove Key from Buffer 0080 CD 16 INT 16H ; Get Keycode in AX 0082 0A C0 OR AL, AL ; Low Byte Set (Ascii?) 0084 74 06 JZ @SK_Exit ; if not, it's a F-Key CLR AH ; Clear ScanCode if Ascii 0086 32 E4 1 xor AH, AH ; Set Register = 0 0088 EB 02 JMP s @SK_Exit ; Return Key in AX 008A @SK_NO_KEY: CLR AX ; Return Nil (no Keypress) 008A 33 C0 1 xor AX, AX ; Set Register = 0 008C @SK_Exit: 008C FC cld ; Reset Direction Flag POPx DI, SI, DS, BP ; Restore Saved Registers 008D 5F 1 pop DI ; Restore R1 008E 5E 2 pop SI ; Restore R1 008F 1F 3 pop DS ; Restore R1 0090 5D 4 pop BP ; Restore R1 0091 CB ret ; Exit & Clean Up Stack 0092 SCAN_KEYBOARD ENDP ;======================================== ;int far pascal random_int (int MaxValue) ;======================================== ; ; Returns a pseudo-random number in the range of (0.. MaxInt-1) ; PUBLIC RANDOM_INT 0008 RI_Stack STRUC 0000 0000 DW ? ; BP 0002 00000000 DD ? ; Caller 0006 0000 RI_MaxVal DW ? ; Maximum Value to Return + 1 RI_Stack ENDS 0092 RANDOM_INT PROC FAR 0092 55 push BP ; Preserve Important Registers 0093 8B EC mov BP, SP ; Set up Stack Frame CLR BX ; BX is the data index 0095 33 DB 1 xor BX, BX ; Set Register = 0 CLR CX ; CX is the accumulator 0097 33 C9 1 xor CX, CX ; Set Register = 0 REPT 3 mov AX, RND_Seed[BX] ; load the initial seed mul RND_Mult[BX] ; multiply it div RND_ModV[BX] ; and obtain the Mod value mov RND_Seed[BX], DX ; save that for the next time add CX, DX ; add it into the accumulator inc BX inc BX ; point to the next set of values ENDM 0099 8B 87 0000 R 1 mov AX, RND_Seed[BX] ; load the initial seed 009D F7 A7 0006 R 1 mul RND_Mult[BX] ; multiply it 00A1 F7 B7 000C R 1 div RND_ModV[BX] ; and obtain the Mod value 00A5 89 97 0000 R 1 mov RND_Seed[BX], DX ; save that for the next time 00A9 03 CA 1 add CX, DX ; add it into the accumulator 00AB 43 1 inc BX 00AC 43 1 inc BX ; point to the next set of values 00AD 8B 87 0000 R 1 mov AX, RND_Seed[BX] ; load the initial seed 00B1 F7 A7 0006 R 1 mul RND_Mult[BX] ; multiply it 00B5 F7 B7 000C R 1 div RND_ModV[BX] ; and obtain the Mod value 00B9 89 97 0000 R 1 mov RND_Seed[BX], DX ; save that for the next time 00BD 03 CA 1 add CX, DX ; add it into the accumulator 00BF 43 1 inc BX 00C0 43 1 inc BX ; point to the next set of values 00C1 8B 87 0000 R 1 mov AX, RND_Seed[BX] ; load the initial seed 00C5 F7 A7 0006 R 1 mul RND_Mult[BX] ; multiply it 00C9 F7 B7 000C R 1 div RND_ModV[BX] ; and obtain the Mod value 00CD 89 97 0000 R 1 mov RND_Seed[BX], DX ; save that for the next time 00D1 03 CA 1 add CX, DX ; add it into the accumulator 00D3 43 1 inc BX 00D4 43 1 inc BX ; point to the next set of values 00D5 8B C1 mov AX, CX ; AX = Random # CLR DX ; DX = 0 00D7 33 D2 1 xor DX, DX ; Set Register = 0 00D9 F7 76 06 div [BP].RI_MaxVal ; DX = DX:AX / MAxVal Remainder 00DC 8B C2 mov AX, DX 00DE 5D pop BP ; Restore BP 00DF CA 0002 ret 2 ; back to BASIC with AX holding the result 00E2 RANDOM_INT ENDP ;================================== ;void far pascal init_random (void) ;================================== ; ; Scrambles the psuedo-random number sequence ; (XOR's the seed value with the timer) ; PUBLIC INIT_RANDOM 00E2 INIT_RANDOM PROC FAR CLR AX ; Segment = 0000 00E2 33 C0 1 xor AX, AX ; Set Register = 0 00E4 8E C0 mov ES, AX 00E6 26: A1 046C mov AX, ES:[046Ch] ; Get Timer Lo Word 00EA 31 06 0000 R xor RND_Seed, AX ; Scramble 1st Seed 00EE CB ret ; Exit & Clean Up Stack 00EF INIT_RANDOM ENDP ;========================================= ;int far pascal int_sqr (int X, int Round) ;========================================= ; ; Returns the Integer Square Root of (X) ; Round allows the return value to be rounded to the ; nearest integer value by passing 0x80. Passing 0 ; return the Integer Portion only. The rounding amound is ; a number from 0 to 1 multiplied by 256, thus ; 0.5 * 0x100 = 0x80! ; 000C ISQ_Stack STRUC 0000 0000 0000 DW ?,? ; BP, DI 0004 00000000 DD ? ; Caller 0008 0000 ISQ_Round DW ? ; Amount to Round Result * 256 000A 0000 ISQ_X DW ? ; "X" ISQ_Stack ENDS PUBLIC INT_SQR 00EF INT_SQR PROC FAR PUSHx BP, DI ; Save BP 00EF 55 1 push BP ; Save R1 00F0 57 2 push DI ; Save R1 00F1 8B EC mov BP, SP ; Set up Stack Frame 00F3 33 C0 xor AX, AX ; {xor eax,eax} 00F5 33 D2 xor DX, DX ; {xor edx,edx} 00F7 8B 7E 0A mov DI, [BP].ISQ_X ; {mov edi,x} 00FA B9 0010 mov CX, 16 ; {mov cx, 32} 00FD @ISQ_L: 00FD D1 E7 shl DI, 1 ; {shl edi,1} 00FF D1 D2 rcl DX, 1 ; {rcl edx,1} 0101 D1 E7 shl DI, 1 ; {shl edi,1} 0103 D1 D2 rcl DX, 1 ; {rcl edx,1} 0105 D1 E0 shl AX, 1 ; {shl eax,1} 0107 8B D8 mov BX, AX ; {mov ebx,eax} 0109 D1 E3 shl BX, 1 ; {shl ebx,1} 010B 43 inc BX ; {inc ebx} 010C 3B D3 cmp DX, BX ; {cmp edx,ebx} 010E 7C 03 jl @ISQ_S 0110 2B D3 sub DX, BX ; {sub edx,ebx} 0112 40 inc AX ; {inc eax} 0113 @ISQ_S: 0113 E2 E8 loop @ISQ_L 0115 03 46 08 add ax, [BP].ISQ_Round ; {add eax,$00008000} ; {*round* result in hi word: ie. +0 .5} 0118 C1 E8 08 shr ax, 8 ; {shr eax,16} {to ax (result)} POPx DI, BP ; Restore Registers 011B 5F 1 pop DI ; Restore R1 011C 5D 2 pop BP ; Restore R1 011D CA 0004 ret 4 ; Exit 0120 INT_SQR ENDP ;================================= ;int far pascal timer_count (void) ;================================= ; ; Returns the current timer value as an integer/long integer ; PUBLIC TIMER_COUNT 0120 TIMER_COUNT PROC FAR CLR AX ; Segment = 0000 0120 33 C0 1 xor AX, AX ; Set Register = 0 0122 8E C0 mov ES, AX 0124 26: A1 046C mov AX, ES:[046Ch] ; Get Timer Lo Word 0128 26: 8B 16 046E mov DX, ES:[046Eh] ; Get Timer Hi Word 012D CB ret ; Exit & Clean Up Stack 012E TIMER_COUNT ENDP END Microsoft (R) Macro Assembler Version 6.11 07/03/14 12:38:18 c_utils.asm Symbols 3 - 1 Macros: N a m e Type CLR . . . . . . . . . . . . . . Proc LOOPjz . . . . . . . . . . . . . Proc LOOPx . . . . . . . . . . . . . Proc POPx . . . . . . . . . . . . . . Proc PUSHx . . . . . . . . . . . . . Proc Microsoft (R) Macro Assembler Version 6.11 07/03/14 12:38:18 c_utils.asm Symbols 4 - 1 Structures and Unions: N a m e Size Offset Type DP_Stack . . . . . . . . . . . . 0010 DP_Text . . . . . . . . . . . 000C DWord ISQ_Stack . . . . . . . . . . . 000C ISQ_Round . . . . . . . . . . 0008 Word ISQ_X . . . . . . . . . . . . 000A Word RI_Stack . . . . . . . . . . . . 0008 RI_MaxVal . . . . . . . . . . 0006 Word SVM_Stack . . . . . . . . . . . 000E SVM_Mode . . . . . . . . . . . 000C Byte Microsoft (R) Macro Assembler Version 6.11 07/03/14 12:38:18 c_utils.asm Symbols 5 - 1 Segments and Groups: N a m e Size Length Align Combine Class C_UTILS_TEXT . . . . . . . . . . 16 Bit 012E Word Public 'CODE' DGROUP . . . . . . . . . . . . . GROUP _DATA . . . . . . . . . . . . . 16 Bit 0014 Word Public 'DATA' Microsoft (R) Macro Assembler Version 6.11 07/03/14 12:38:18 c_utils.asm Symbols 6 - 1 Procedures, parameters and locals: N a m e Type Value Attr DOS_PRINTS . . . . . . . . . . . P Far 0039 C_UTILS_TEXT Length= 0027 Public DOS_PRINT . . . . . . . . . . . P Far 0000 C_UTILS_TEXT Length= 0039 Public INIT_RANDOM . . . . . . . . . . P Far 00E2 C_UTILS_TEXT Length= 000D Public INT_SQR . . . . . . . . . . . . P Far 00EF C_UTILS_TEXT Length= 0031 Public RANDOM_INT . . . . . . . . . . . P Far 0092 C_UTILS_TEXT Length= 0050 Public SCAN_KEYBOARD . . . . . . . . . P Far 0074 C_UTILS_TEXT Length= 001E Public SET_VIDEO_MODE . . . . . . . . . P Far 0060 C_UTILS_TEXT Length= 0014 Public TIMER_COUNT . . . . . . . . . . P Far 0120 C_UTILS_TEXT Length= 000E Public Microsoft (R) Macro Assembler Version 6.11 07/03/14 12:38:18 c_utils.asm Symbols 7 - 1 Symbols: N a m e Type Value Attr ?x3 . . . . . . . . . . . . . . Text ?,?,? ?x4 . . . . . . . . . . . . . . Text ?,?,?,? @@DPS_Got_len . . . . . . . . . L Near 004F C_UTILS_TEXT @@DPS_Scan_it . . . . . . . . . L Near 0046 C_UTILS_TEXT @@DP_Got_len . . . . . . . . . . L Near 0016 C_UTILS_TEXT @@DP_Scan_it . . . . . . . . . . L Near 000D C_UTILS_TEXT @CodeSize . . . . . . . . . . . Number 0001h @DPS_Exit . . . . . . . . . . . L Near 0058 C_UTILS_TEXT @DataSize . . . . . . . . . . . Number 0000h @ISQ_L . . . . . . . . . . . . . L Near 00FD C_UTILS_TEXT @ISQ_S . . . . . . . . . . . . . L Near 0113 C_UTILS_TEXT @Interface . . . . . . . . . . . Number 0000h @Model . . . . . . . . . . . . . Number 0004h @No_Print . . . . . . . . . . . L Near 001F C_UTILS_TEXT @SK_Exit . . . . . . . . . . . . L Near 008C C_UTILS_TEXT @SK_NO_KEY . . . . . . . . . . . L Near 008A C_UTILS_TEXT @SVM_Exit . . . . . . . . . . . L Near 006D C_UTILS_TEXT @code . . . . . . . . . . . . . Text C_UTILS_TEXT @data . . . . . . . . . . . . . Text DGROUP @fardata? . . . . . . . . . . . Text FAR_BSS @fardata . . . . . . . . . . . . Text FAR_DATA @stack . . . . . . . . . . . . . Text DGROUP CR_LF . . . . . . . . . . . . . Byte 0012 _DATA False . . . . . . . . . . . . . Number 0000h RND_ModV . . . . . . . . . . . . Word 000C _DATA RND_Mult . . . . . . . . . . . . Word 0006 _DATA RND_Seed . . . . . . . . . . . . Word 0000 _DATA True . . . . . . . . . . . . . . Number -0001h b . . . . . . . . . . . . . . . Text BYTE PTR d . . . . . . . . . . . . . . . Text DWORD PTR f . . . . . . . . . . . . . . . Text FAR PTR nil . . . . . . . . . . . . . . Number 0000h o . . . . . . . . . . . . . . . Text OFFSET s . . . . . . . . . . . . . . . Text SHORT w . . . . . . . . . . . . . . . Text WORD PTR 0 Warnings 0 Errors