--- /dev/null
+Microsoft (R) Macro Assembler Version 6.11 07/03/14 12:38:18\r
+c_utils.asm Page 1 - 1\r
+\r
+\r
+ ;=======================================================\r
+ ;=== C_UTILS.ASM - Asm Utilities for C/C++ ===\r
+ ;=======================================================\r
+\r
+ PAGE 255, 132\r
+\r
+ .MODEL Medium\r
+ .286\r
+\r
+ ; ==== MACROS ====\r
+\r
+ ; macros to PUSH and POP multiple registers\r
+\r
+ PUSHx MACRO R1, R2, R3, R4, R5, R6, R7, R8\r
+ IFNB <R1>\r
+ push R1 ; Save R1\r
+ PUSHx R2, R3, R4, R5, R6, R7, R8\r
+ ENDIF\r
+ ENDM\r
+\r
+ POPx MACRO R1, R2, R3, R4, R5, R6, R7, R8\r
+ IFNB <R1>\r
+ pop R1 ; Restore R1\r
+ POPx R2, R3, R4, R5, R6, R7, R8\r
+ ENDIF\r
+ ENDM\r
+\r
+ ; Macro to Clear a Register to 0\r
+\r
+ CLR MACRO Register\r
+ xor Register, Register ; Set Register = 0\r
+ ENDM\r
+\r
+ ; Macros to Decrement Counter & Jump on Condition\r
+\r
+ LOOPx MACRO Register, Destination\r
+ dec Register ; Counter--\r
+ jnz Destination ; Jump if not 0\r
+ ENDM\r
+\r
+ LOOPjz MACRO Register, Destination\r
+ dec Register ; Counter--\r
+ jz Destination ; Jump if 0\r
+ ENDM\r
+\r
+\r
+ ; ==== General Constants ====\r
+\r
+ = 0000 False EQU 0\r
+ =-0001 True EQU -1\r
+ = 0000 nil EQU 0\r
+\r
+ = BYTE PTR b EQU BYTE PTR\r
+ = WORD PTR w EQU WORD PTR\r
+ = DWORD PTR d EQU DWORD PTR\r
+ = OFFSET o EQU OFFSET\r
+ = FAR PTR f EQU FAR PTR\r
+ = SHORT s EQU SHORT\r
+ = ?,?,?,? ?x4 EQU <?,?,?,?>\r
+ = ?,?,? ?x3 EQU <?,?,?>\r
+\r
+\r
+ 0000 .Data\r
+\r
+ EVEN\r
+\r
+ 0000 1CE5 7307 0322 RND_Seed DW 7397, 29447, 802\r
+ 0006 00B3 00B7 00B6 RND_Mult DW 179, 183, 182\r
+ 000C 8003 800B 800F RND_ModV DW 32771, 32779, 32783\r
+\r
+ 0012 0D 0A CR_LF DB 13, 10 ; the CRLF data\r
+\r
+ 0000 .Code\r
+\r
+ ;===========================================\r
+ ;void far pascal dos_print (far char *Text)\r
+ ;===========================================\r
+ ;\r
+ ; - Print Text Directly to DOS console w/ CR/LF\r
+ ;\r
+\r
+ PUBLIC DOS_PRINT\r
+\r
+ 0010 DP_Stack STRUC\r
+ 0000 0000 0000 0000 DW ?x4 ; DI, SI, DS, BP\r
+ 0000\r
+ 0008 00000000 DD ? ; Caller\r
+ 000C 00000000 DP_Text DD ? ; Far Address of Text to print\r
+ DP_Stack ENDS\r
+\r
+\r
+ 0000 DOS_PRINT PROC FAR\r
+ \r
+ PUSHx BP, DS, SI, DI ; Preserve Important Registers\r
+ 0000 55 1 push BP ; Save R1\r
+ 0001 1E 2 push DS ; Save R1\r
+ 0002 56 3 push SI ; Save R1\r
+ 0003 57 4 push DI ; Save R1\r
+ 0004 8B EC mov BP, SP ; Set up Stack Frame\r
+\r
+ 0006 C5 56 0C lds DX, [BP].DP_Text ; Get Addr of Text$ descriptor\r
+\r
+ ; Compute Length of string\r
+\r
+ CLR CX ; Length = 0\r
+ 0009 33 C9 1 xor CX, CX ; Set Register = 0\r
+ 000B 8B F2 mov SI, DX ; DS:SI = String data\r
+\r
+ 000D @@DP_Scan_it:\r
+ \r
+ 000D 80 3C 00 cmp b [SI], 0 ; Null Byte found?\r
+ 0010 74 04 je @@DP_Got_Len ; exit loop if so\r
+\r
+ 0012 41 inc CX ; Len++\r
+ 0013 46 inc SI ; Point to next char\r
+ 0014 EB F7 jmp s @@DP_Scan_it ; check again...\r
+\r
+ 0016 @@DP_Got_len:\r
+\r
+ 0016 E3 07 jcxz @No_Print ; Don't Print if empty\r
+\r
+ 0018 BB 0001 mov BX, 1 ; 1= DOS Handle for Display\r
+ 001B B4 40 mov AH, 40h ; Write Text Function\r
+ 001D CD 21 int 21h ; Call DOS to do it\r
+\r
+ 001F @No_Print:\r
+ 001F B8 ---- R mov AX, SEG DGROUP ; Restore DGroup\r
+ 0022 8E D8 mov DS, AX\r
+\r
+ 0024 BA 0012 R mov DX, o CR_LF ; Get Addr of CR/LF pair\r
+ 0027 B9 0002 mov CX, 2 ; 2 Characters to Write \r
+ 002A BB 0001 mov BX, 1 ; 1= DOS Handle for Display\r
+\r
+ 002D B4 40 mov AH, 40h ; Write Text Function\r
+ 002F CD 21 int 21h ; Call DOS to do it\r
+\r
+ 0031 FC cld ; Reset Direction Flag \r
+ POPx DI, SI, DS, BP ; Restore Saved Registers\r
+ 0032 5F 1 pop DI ; Restore R1\r
+ 0033 5E 2 pop SI ; Restore R1\r
+ 0034 1F 3 pop DS ; Restore R1\r
+ 0035 5D 4 pop BP ; Restore R1\r
+ 0036 CA 0004 ret 4 ; Exit & Clean Up Stack\r
+\r
+ 0039 DOS_PRINT ENDP\r
+\r
+\r
+ ;===========================================\r
+ ;void far pascal dos_prints (char far *Text)\r
+ ;===========================================\r
+ ; \r
+ ; Print Text Directly to DOS console \r
+ ; without a trailing CR/LF\r
+ ;\r
+\r
+ PUBLIC DOS_PRINTS\r
+\r
+ 0039 DOS_PRINTS PROC FAR\r
+\r
+ PUSHx BP, DS, SI, DI ; Preserve Important Registers\r
+ 0039 55 1 push BP ; Save R1\r
+ 003A 1E 2 push DS ; Save R1\r
+ 003B 56 3 push SI ; Save R1\r
+ 003C 57 4 push DI ; Save R1\r
+ 003D 8B EC mov BP, SP ; Set up Stack Frame\r
+\r
+ 003F C5 56 0C lds DX, [BP].DP_Text ; Get Addr of Text$ descriptor\r
+\r
+ ; Compute Length of string\r
+\r
+ CLR CX ; Length = 0\r
+ 0042 33 C9 1 xor CX, CX ; Set Register = 0\r
+ 0044 8B F2 mov SI, DX ; DS:SI = String data\r
+\r
+ 0046 @@DPS_Scan_it:\r
+ \r
+ 0046 80 3C 00 cmp b [SI], 0 ; Null Byte found?\r
+ 0049 74 04 je @@DPS_Got_Len ; exit loop if so\r
+\r
+ 004B 41 inc CX ; Len++\r
+ 004C 46 inc SI ; Point to next char\r
+ 004D EB F7 jmp s @@DPS_Scan_it ; check again...\r
+\r
+ 004F @@DPS_Got_len:\r
+\r
+ 004F E3 07 jcxz @DPS_Exit ; Don't Print if empty\r
+\r
+ 0051 BB 0001 mov BX, 1 ; 1= DOS Handle for Display\r
+ 0054 B4 40 mov AH, 40h ; Write Text Function\r
+ 0056 CD 21 int 21h ; Call DOS to do it\r
+\r
+ 0058 @DPS_Exit:\r
+ 0058 FC cld ; Reset Direction Flag \r
+ POPx DI, SI, DS, BP ; Restore Saved Registers\r
+ 0059 5F 1 pop DI ; Restore R1\r
+ 005A 5E 2 pop SI ; Restore R1\r
+ 005B 1F 3 pop DS ; Restore R1\r
+ 005C 5D 4 pop BP ; Restore R1\r
+ 005D CA 0002 ret 2 ; Exit & Clean Up Stack\r
+\r
+ 0060 DOS_PRINTS ENDP\r
+\r
+\r
+ ;=========================================\r
+ ;void far pascal set_video_mode (int Mode)\r
+ ;=========================================\r
+ ;\r
+ ; Sets the Video Mode through the BIOS\r
+ ;\r
+\r
+ PUBLIC SET_VIDEO_MODE\r
+\r
+ 000E SVM_Stack STRUC\r
+ 0000 0000 0000 0000 DW ?x4 ; DI, SI, DS, BP\r
+ 0000\r
+ 0008 00000000 DD ? ; Caller\r
+ 000C 00 00 SVM_Mode DB ?,? ; Desired Video Mode\r
+ SVM_Stack ENDS\r
+\r
+\r
+ 0060 SET_VIDEO_MODE PROC FAR\r
+\r
+ PUSHx BP, DS, SI, DI ; Preserve Important Registers\r
+ 0060 55 1 push BP ; Save R1\r
+ 0061 1E 2 push DS ; Save R1\r
+ 0062 56 3 push SI ; Save R1\r
+ 0063 57 4 push DI ; Save R1\r
+ 0064 8B EC mov BP, SP ; Set up Stack Frame\r
+\r
+ CLR AH ; Function 0\r
+ 0066 32 E4 1 xor AH, AH ; Set Register = 0\r
+ 0068 8A 46 0C mov AL, [BP].SVM_Mode ; Get Mode #\r
+\r
+ 006B CD 10 int 10H ; Change Video Modes\r
+\r
+ 006D @SVM_Exit:\r
+ POPx DI, SI, DS, BP ; Restore Saved Registers\r
+ 006D 5F 1 pop DI ; Restore R1\r
+ 006E 5E 2 pop SI ; Restore R1\r
+ 006F 1F 3 pop DS ; Restore R1\r
+ 0070 5D 4 pop BP ; Restore R1\r
+ 0071 CA 0002 ret 2 ; Exit & Clean Up Stack\r
+\r
+ 0074 SET_VIDEO_MODE ENDP\r
+\r
+\r
+ ;===================================\r
+ ;int far pascal scan_keyboard (void)\r
+ ;===================================\r
+ ;\r
+ ; Function to scan keyboard for a pressed key\r
+ ;\r
+\r
+ PUBLIC SCAN_KEYBOARD\r
+\r
+ 0074 SCAN_KEYBOARD PROC FAR\r
+\r
+ PUSHx BP, DS, SI, DI ; Preserve Important Registers\r
+ 0074 55 1 push BP ; Save R1\r
+\fMicrosoft (R) Macro Assembler Version 6.11 07/03/14 12:38:18\r
+c_utils.asm Page 2 - 1\r
+\r
+\r
+ 0075 1E 2 push DS ; Save R1\r
+ 0076 56 3 push SI ; Save R1\r
+ 0077 57 4 push DI ; Save R1\r
+\r
+ 0078 B4 01 mov AH, 01H ; Function #1\r
+ 007A CD 16 INT 16H ; Call Keyboard Driver\r
+ 007C 74 0C JZ @SK_NO_KEY ; Exit if Zero flag set\r
+\r
+ 007E B4 00 mov AH, 00H ; Remove Key from Buffer\r
+ 0080 CD 16 INT 16H ; Get Keycode in AX\r
+\r
+ 0082 0A C0 OR AL, AL ; Low Byte Set (Ascii?)\r
+ 0084 74 06 JZ @SK_Exit ; if not, it's a F-Key\r
+\r
+ CLR AH ; Clear ScanCode if Ascii\r
+ 0086 32 E4 1 xor AH, AH ; Set Register = 0\r
+ 0088 EB 02 JMP s @SK_Exit ; Return Key in AX\r
+\r
+ 008A @SK_NO_KEY:\r
+ CLR AX ; Return Nil (no Keypress)\r
+ 008A 33 C0 1 xor AX, AX ; Set Register = 0\r
+\r
+ 008C @SK_Exit:\r
+ 008C FC cld ; Reset Direction Flag \r
+ POPx DI, SI, DS, BP ; Restore Saved Registers\r
+ 008D 5F 1 pop DI ; Restore R1\r
+ 008E 5E 2 pop SI ; Restore R1\r
+ 008F 1F 3 pop DS ; Restore R1\r
+ 0090 5D 4 pop BP ; Restore R1\r
+ 0091 CB ret ; Exit & Clean Up Stack\r
+\r
+ 0092 SCAN_KEYBOARD ENDP\r
+\r
+\r
+ ;========================================\r
+ ;int far pascal random_int (int MaxValue)\r
+ ;========================================\r
+ ;\r
+ ; Returns a pseudo-random number in the range of (0.. MaxInt-1)\r
+ ;\r
+\r
+\r
+ PUBLIC RANDOM_INT\r
+\r
+ 0008 RI_Stack STRUC\r
+ 0000 0000 DW ? ; BP\r
+ 0002 00000000 DD ? ; Caller\r
+ 0006 0000 RI_MaxVal DW ? ; Maximum Value to Return + 1\r
+ RI_Stack ENDS\r
+\r
+\r
+ 0092 RANDOM_INT PROC FAR\r
+\r
+ 0092 55 push BP ; Preserve Important Registers\r
+ 0093 8B EC mov BP, SP ; Set up Stack Frame\r
+\r
+ CLR BX ; BX is the data index\r
+ 0095 33 DB 1 xor BX, BX ; Set Register = 0\r
+ CLR CX ; CX is the accumulator\r
+ 0097 33 C9 1 xor CX, CX ; Set Register = 0\r
+\r
+ REPT 3\r
+ mov AX, RND_Seed[BX] ; load the initial seed\r
+ mul RND_Mult[BX] ; multiply it\r
+ div RND_ModV[BX] ; and obtain the Mod value\r
+ mov RND_Seed[BX], DX ; save that for the next time\r
+\r
+ add CX, DX ; add it into the accumulator\r
+ inc BX\r
+ inc BX ; point to the next set of values\r
+ ENDM\r
+ 0099 8B 87 0000 R 1 mov AX, RND_Seed[BX] ; load the initial seed\r
+ 009D F7 A7 0006 R 1 mul RND_Mult[BX] ; multiply it\r
+ 00A1 F7 B7 000C R 1 div RND_ModV[BX] ; and obtain the Mod value\r
+ 00A5 89 97 0000 R 1 mov RND_Seed[BX], DX ; save that for the next time\r
+ 00A9 03 CA 1 add CX, DX ; add it into the accumulator\r
+ 00AB 43 1 inc BX\r
+ 00AC 43 1 inc BX ; point to the next set of values\r
+ 00AD 8B 87 0000 R 1 mov AX, RND_Seed[BX] ; load the initial seed\r
+ 00B1 F7 A7 0006 R 1 mul RND_Mult[BX] ; multiply it\r
+ 00B5 F7 B7 000C R 1 div RND_ModV[BX] ; and obtain the Mod value\r
+ 00B9 89 97 0000 R 1 mov RND_Seed[BX], DX ; save that for the next time\r
+ 00BD 03 CA 1 add CX, DX ; add it into the accumulator\r
+ 00BF 43 1 inc BX\r
+ 00C0 43 1 inc BX ; point to the next set of values\r
+ 00C1 8B 87 0000 R 1 mov AX, RND_Seed[BX] ; load the initial seed\r
+ 00C5 F7 A7 0006 R 1 mul RND_Mult[BX] ; multiply it\r
+ 00C9 F7 B7 000C R 1 div RND_ModV[BX] ; and obtain the Mod value\r
+ 00CD 89 97 0000 R 1 mov RND_Seed[BX], DX ; save that for the next time\r
+ 00D1 03 CA 1 add CX, DX ; add it into the accumulator\r
+ 00D3 43 1 inc BX\r
+ 00D4 43 1 inc BX ; point to the next set of values\r
+\r
+ 00D5 8B C1 mov AX, CX ; AX = Random #\r
+ CLR DX ; DX = 0\r
+ 00D7 33 D2 1 xor DX, DX ; Set Register = 0\r
+ 00D9 F7 76 06 div [BP].RI_MaxVal ; DX = DX:AX / MAxVal Remainder\r
+\r
+ 00DC 8B C2 mov AX, DX\r
+\r
+ 00DE 5D pop BP ; Restore BP\r
+ 00DF CA 0002 ret 2 ; back to BASIC with AX holding the result\r
+\r
+ 00E2 RANDOM_INT ENDP\r
+\r
+\r
+ ;==================================\r
+ ;void far pascal init_random (void)\r
+ ;==================================\r
+ ;\r
+ ; Scrambles the psuedo-random number sequence\r
+ ; (XOR's the seed value with the timer)\r
+ ;\r
+\r
+ PUBLIC INIT_RANDOM\r
+\r
+ 00E2 INIT_RANDOM PROC FAR\r
+\r
+ CLR AX ; Segment = 0000\r
+ 00E2 33 C0 1 xor AX, AX ; Set Register = 0\r
+ 00E4 8E C0 mov ES, AX\r
+ 00E6 26: A1 046C mov AX, ES:[046Ch] ; Get Timer Lo Word\r
+\r
+ 00EA 31 06 0000 R xor RND_Seed, AX ; Scramble 1st Seed\r
+\r
+ 00EE CB ret ; Exit & Clean Up Stack\r
+\r
+ 00EF INIT_RANDOM ENDP\r
+\r
+ ;=========================================\r
+ ;int far pascal int_sqr (int X, int Round)\r
+ ;=========================================\r
+ ;\r
+ ; Returns the Integer Square Root of (X)\r
+ ; Round allows the return value to be rounded to the \r
+ ; nearest integer value by passing 0x80. Passing 0\r
+ ; return the Integer Portion only. The rounding amound is\r
+ ; a number from 0 to 1 multiplied by 256, thus \r
+ ; 0.5 * 0x100 = 0x80!\r
+ ;\r
+\r
+ 000C ISQ_Stack STRUC\r
+ 0000 0000 0000 DW ?,? ; BP, DI\r
+ 0004 00000000 DD ? ; Caller\r
+ 0008 0000 ISQ_Round DW ? ; Amount to Round Result * 256\r
+ 000A 0000 ISQ_X DW ? ; "X"\r
+ ISQ_Stack ENDS\r
+\r
+ PUBLIC INT_SQR\r
+\r
+ 00EF INT_SQR PROC FAR\r
+\r
+ PUSHx BP, DI ; Save BP\r
+ 00EF 55 1 push BP ; Save R1\r
+ 00F0 57 2 push DI ; Save R1\r
+ 00F1 8B EC mov BP, SP ; Set up Stack Frame\r
+\r
+ 00F3 33 C0 xor AX, AX ; {xor eax,eax}\r
+ 00F5 33 D2 xor DX, DX ; {xor edx,edx}\r
+ 00F7 8B 7E 0A mov DI, [BP].ISQ_X ; {mov edi,x}\r
+\r
+ 00FA B9 0010 mov CX, 16 ; {mov cx, 32}\r
+\r
+ 00FD @ISQ_L:\r
+\r
+ 00FD D1 E7 shl DI, 1 ; {shl edi,1}\r
+ 00FF D1 D2 rcl DX, 1 ; {rcl edx,1}\r
+ 0101 D1 E7 shl DI, 1 ; {shl edi,1}\r
+ 0103 D1 D2 rcl DX, 1 ; {rcl edx,1}\r
+ 0105 D1 E0 shl AX, 1 ; {shl eax,1}\r
+ 0107 8B D8 mov BX, AX ; {mov ebx,eax}\r
+ 0109 D1 E3 shl BX, 1 ; {shl ebx,1}\r
+ 010B 43 inc BX ; {inc ebx}\r
+ 010C 3B D3 cmp DX, BX ; {cmp edx,ebx}\r
+ 010E 7C 03 jl @ISQ_S\r
+\r
+ 0110 2B D3 sub DX, BX ; {sub edx,ebx}\r
+ 0112 40 inc AX ; {inc eax}\r
+\r
+ 0113 @ISQ_S: \r
+ 0113 E2 E8 loop @ISQ_L\r
+\r
+ 0115 03 46 08 add ax, [BP].ISQ_Round ; {add eax,$00008000} \r
+ ; {*round* result in hi word: ie. +0\r
+ .5}\r
+ 0118 C1 E8 08 shr ax, 8 ; {shr eax,16} {to ax (result)}\r
+\r
+ POPx DI, BP ; Restore Registers \r
+ 011B 5F 1 pop DI ; Restore R1\r
+ 011C 5D 2 pop BP ; Restore R1\r
+ 011D CA 0004 ret 4 ; Exit\r
+\r
+ 0120 INT_SQR ENDP\r
+\r
+ ;=================================\r
+ ;int far pascal timer_count (void)\r
+ ;=================================\r
+ ;\r
+ ; Returns the current timer value as an integer/long integer\r
+ ;\r
+\r
+ PUBLIC TIMER_COUNT\r
+\r
+ 0120 TIMER_COUNT PROC FAR\r
+\r
+ CLR AX ; Segment = 0000\r
+ 0120 33 C0 1 xor AX, AX ; Set Register = 0\r
+ 0122 8E C0 mov ES, AX\r
+ 0124 26: A1 046C mov AX, ES:[046Ch] ; Get Timer Lo Word\r
+ 0128 26: 8B 16 046E mov DX, ES:[046Eh] ; Get Timer Hi Word\r
+ 012D CB ret ; Exit & Clean Up Stack\r
+\r
+ 012E TIMER_COUNT ENDP\r
+\r
+\r
+ END\r
+\fMicrosoft (R) Macro Assembler Version 6.11 07/03/14 12:38:18\r
+c_utils.asm Symbols 3 - 1\r
+\r
+\r
+\r
+\r
+Macros:\r
+\r
+ N a m e Type\r
+\r
+CLR . . . . . . . . . . . . . . Proc\r
+LOOPjz . . . . . . . . . . . . . Proc\r
+LOOPx . . . . . . . . . . . . . Proc\r
+POPx . . . . . . . . . . . . . . Proc\r
+PUSHx . . . . . . . . . . . . . Proc\r
+\fMicrosoft (R) Macro Assembler Version 6.11 07/03/14 12:38:18\r
+c_utils.asm Symbols 4 - 1\r
+\r
+\r
+\r
+\r
+Structures and Unions:\r
+\r
+ N a m e Size\r
+ Offset Type\r
+\r
+DP_Stack . . . . . . . . . . . . 0010\r
+ DP_Text . . . . . . . . . . . 000C DWord\r
+ISQ_Stack . . . . . . . . . . . 000C\r
+ ISQ_Round . . . . . . . . . . 0008 Word\r
+ ISQ_X . . . . . . . . . . . . 000A Word\r
+RI_Stack . . . . . . . . . . . . 0008\r
+ RI_MaxVal . . . . . . . . . . 0006 Word\r
+SVM_Stack . . . . . . . . . . . 000E\r
+ SVM_Mode . . . . . . . . . . . 000C Byte\r
+\fMicrosoft (R) Macro Assembler Version 6.11 07/03/14 12:38:18\r
+c_utils.asm Symbols 5 - 1\r
+\r
+\r
+\r
+\r
+Segments and Groups:\r
+\r
+ N a m e Size Length Align Combine Class\r
+\r
+C_UTILS_TEXT . . . . . . . . . . 16 Bit 012E Word Public 'CODE' \r
+DGROUP . . . . . . . . . . . . . GROUP\r
+_DATA . . . . . . . . . . . . . 16 Bit 0014 Word Public 'DATA' \r
+\fMicrosoft (R) Macro Assembler Version 6.11 07/03/14 12:38:18\r
+c_utils.asm Symbols 6 - 1\r
+\r
+\r
+\r
+\r
+Procedures, parameters and locals:\r
+\r
+ N a m e Type Value Attr\r
+\r
+DOS_PRINTS . . . . . . . . . . . P Far 0039 C_UTILS_TEXT Length= 0027 Public\r
+DOS_PRINT . . . . . . . . . . . P Far 0000 C_UTILS_TEXT Length= 0039 Public\r
+INIT_RANDOM . . . . . . . . . . P Far 00E2 C_UTILS_TEXT Length= 000D Public\r
+INT_SQR . . . . . . . . . . . . P Far 00EF C_UTILS_TEXT Length= 0031 Public\r
+RANDOM_INT . . . . . . . . . . . P Far 0092 C_UTILS_TEXT Length= 0050 Public\r
+SCAN_KEYBOARD . . . . . . . . . P Far 0074 C_UTILS_TEXT Length= 001E Public\r
+SET_VIDEO_MODE . . . . . . . . . P Far 0060 C_UTILS_TEXT Length= 0014 Public\r
+TIMER_COUNT . . . . . . . . . . P Far 0120 C_UTILS_TEXT Length= 000E Public\r
+\fMicrosoft (R) Macro Assembler Version 6.11 07/03/14 12:38:18\r
+c_utils.asm Symbols 7 - 1\r
+\r
+\r
+\r
+\r
+Symbols:\r
+\r
+ N a m e Type Value Attr\r
+\r
+?x3 . . . . . . . . . . . . . . Text ?,?,?\r
+?x4 . . . . . . . . . . . . . . Text ?,?,?,?\r
+@@DPS_Got_len . . . . . . . . . L Near 004F C_UTILS_TEXT \r
+@@DPS_Scan_it . . . . . . . . . L Near 0046 C_UTILS_TEXT \r
+@@DP_Got_len . . . . . . . . . . L Near 0016 C_UTILS_TEXT \r
+@@DP_Scan_it . . . . . . . . . . L Near 000D C_UTILS_TEXT \r
+@CodeSize . . . . . . . . . . . Number 0001h \r
+@DPS_Exit . . . . . . . . . . . L Near 0058 C_UTILS_TEXT \r
+@DataSize . . . . . . . . . . . Number 0000h \r
+@ISQ_L . . . . . . . . . . . . . L Near 00FD C_UTILS_TEXT \r
+@ISQ_S . . . . . . . . . . . . . L Near 0113 C_UTILS_TEXT \r
+@Interface . . . . . . . . . . . Number 0000h \r
+@Model . . . . . . . . . . . . . Number 0004h \r
+@No_Print . . . . . . . . . . . L Near 001F C_UTILS_TEXT \r
+@SK_Exit . . . . . . . . . . . . L Near 008C C_UTILS_TEXT \r
+@SK_NO_KEY . . . . . . . . . . . L Near 008A C_UTILS_TEXT \r
+@SVM_Exit . . . . . . . . . . . L Near 006D C_UTILS_TEXT \r
+@code . . . . . . . . . . . . . Text C_UTILS_TEXT\r
+@data . . . . . . . . . . . . . Text DGROUP\r
+@fardata? . . . . . . . . . . . Text FAR_BSS\r
+@fardata . . . . . . . . . . . . Text FAR_DATA\r
+@stack . . . . . . . . . . . . . Text DGROUP\r
+CR_LF . . . . . . . . . . . . . Byte 0012 _DATA \r
+False . . . . . . . . . . . . . Number 0000h \r
+RND_ModV . . . . . . . . . . . . Word 000C _DATA \r
+RND_Mult . . . . . . . . . . . . Word 0006 _DATA \r
+RND_Seed . . . . . . . . . . . . Word 0000 _DATA \r
+True . . . . . . . . . . . . . . Number -0001h \r
+b . . . . . . . . . . . . . . . Text BYTE PTR\r
+d . . . . . . . . . . . . . . . Text DWORD PTR\r
+f . . . . . . . . . . . . . . . Text FAR PTR\r
+nil . . . . . . . . . . . . . . Number 0000h \r
+o . . . . . . . . . . . . . . . Text OFFSET\r
+s . . . . . . . . . . . . . . . Text SHORT\r
+w . . . . . . . . . . . . . . . Text WORD PTR\r
+\r
+ 0 Warnings\r
+ 0 Errors\r
--- /dev/null
+#include <dos.h>\r
+#include <string.h>\r
+#include <mem.h>\r
+#include <conio.h>\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include "modex16.h"\r
+\r
+\r
+byte far* VGA=(byte far*) 0xA0000000; /* this points to video memory. */\r
+\r
+static void fadePalette(sbyte fade, sbyte start, word iter, byte *palette);\r
+static byte tmppal[PAL_SIZE];\r
+static struct pcxHeader {\r
+ byte id;\r
+ byte version;\r
+ byte encoding;\r
+ byte bpp;\r
+ word xmin;\r
+ word ymin;\r
+ word xmax;\r
+ word ymax;\r
+ word hres;\r
+ word vres;\r
+ byte pal16[48];\r
+ byte res1;\r
+ word bpplane;\r
+ word palType;\r
+ word hScreenSize;\r
+ word vScreenSize;\r
+ byte padding[54];\r
+};\r
+\r
+\r
+static void\r
+vgaSetMode(byte mode)\r
+{\r
+ union REGS regs;\r
+\r
+ regs.h.ah = SET_MODE;\r
+ regs.h.al = mode;\r
+ int86(VIDEO_INT, ®s, ®s);\r
+}\r
+\r
+\r
+/* -========================= Entry Points ==========================- */\r
+void\r
+modexEnter() {\r
+ word i;\r
+ dword far*ptr=(dword far*)VGA; /* used for faster screen clearing */\r
+ word CRTParms[] = {\r
+ 0x0d06, /* vertical total */\r
+ 0x3e07, /* overflow (bit 8 of vertical counts) */\r
+ 0x4109, /* cell height (2 to double-scan */\r
+ 0xea10, /* v sync start */\r
+ 0xac11, /* v sync end and protect cr0-cr7 */\r
+ 0xdf12, /* vertical displayed */\r
+ 0x0014, /* turn off dword mode */\r
+ 0xe715, /* v blank start */\r
+ 0x0616, /* v blank end */\r
+ 0xe317 /* turn on byte mode */\r
+ };\r
+ int CRTParmCount = sizeof(CRTParms) / sizeof(CRTParms[0]);\r
+\r
+ /* TODO save current video mode and palette */\r
+ vgaSetMode(VGA_256_COLOR_MODE);\r
+\r
+ /* disable chain4 mode */\r
+ outpw(SC_INDEX, 0x0604);\r
+\r
+ /* synchronous reset while setting Misc Output */\r
+ outpw(SC_INDEX, 0x0100);\r
+\r
+ /* select 25 MHz dot clock & 60 Hz scanning rate */\r
+ outp(MISC_OUTPUT, 0xe3);\r
+\r
+ /* undo reset (restart sequencer) */\r
+ outpw(SC_INDEX, 0x0300);\r
+\r
+ /* reprogram the CRT controller */\r
+ outp(CRTC_INDEX, 0x11); /* VSync End reg contains register write prot */\r
+ outp(CRTC_DATA, 0x7f); /* get current write protect on varios regs */\r
+\r
+ /* send the CRTParms */\r
+ for(i=0; i<CRTParmCount; i++) {\r
+ outpw(CRTC_INDEX, CRTParms[i]);\r
+ }\r
+\r
+ /* clear video memory */\r
+ outpw(SC_INDEX, 0x0f02);\r
+ for(i=0; i<0x8000; i++) {\r
+ ptr[i] = 0x0000;\r
+ }\r
+}\r
+\r
+\r
+void\r
+modexLeave() {\r
+ /* TODO restore original mode and palette */\r
+ vgaSetMode(TEXT_MODE);\r
+}\r
+\r
+\r
+void\r
+modexShowPage(page_t page) {\r
+ word high_address;\r
+ word low_address;\r
+\r
+ high_address = HIGH_ADDRESS | ((word)(page) & 0xff00);\r
+ low_address = LOW_ADDRESS | ((word)(page) << 8);\r
+\r
+ /* wait for appropriate timing */\r
+ while ((inp(INPUT_STATUS_1) & DISPLAY_ENABLE));\r
+ outpw(CRTC_INDEX, high_address);\r
+ outpw(CRTC_INDEX, low_address);\r
+\r
+ /* wait for one retrace */\r
+ while (!(inp(INPUT_STATUS_1) & VRETRACE)); \r
+}\r
+\r
+\r
+void\r
+modexPanPage(page_t *page, int dx, int dy) {\r
+ /* TODO figure out how the $@#! you do horizontal panning */\r
+ *page += dy * SCREEN_WIDTH;\r
+}\r
+\r
+\r
+void\r
+modexSelectPlane(byte plane) {\r
+ outp(SC_INDEX, MAP_MASK); /* select plane */\r
+ outp(SC_DATA, plane);\r
+}\r
+\r
+\r
+void\r
+modexClearRegion(page_t page, int x, int y, int w, int h, byte color) {\r
+ byte plane;\r
+ word endx = x + w;\r
+ word endy = y + h;\r
+ word dx, dy;\r
+\r
+ /* TODO Make this fast. It's SLOOOOOOW */\r
+ for(plane=0; plane < 4; plane++) {\r
+ modexSelectPlane(PLANE(plane+x));\r
+ for(dx = x; dx < endx; dx+=4) {\r
+ for(dy=y; dy<endy; dy++) {\r
+ page[PAGE_OFFSET(dx, dy)] = color;\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+\r
+void\r
+modexDrawBmp(page_t page, int x, int y, bitmap_t *bmp, byte sprite) {\r
+ byte plane;\r
+ word px, py;\r
+ word offset;\r
+\r
+ /* TODO Make this fast. It's SLOOOOOOW */\r
+ for(plane=0; plane < 4; plane++) {\r
+ modexSelectPlane(PLANE(plane+x));\r
+ for(px = plane; px < bmp->width; px+=4) {\r
+ offset=px;\r
+ for(py=0; py<bmp->height; py++) {\r
+ if(!sprite || bmp->data[offset])\r
+ page[PAGE_OFFSET(x+px, y+py)] = bmp->data[offset];\r
+ offset+=bmp->width;\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+\r
+/* fade and flash */\r
+void\r
+modexFadeOn(word fade, byte *palette) {\r
+ fadePalette(-fade, 64, 64/fade+1, palette);\r
+}\r
+\r
+\r
+void\r
+modexFadeOff(word fade, byte *palette) {\r
+ fadePalette(fade, 0, 64/fade+1, palette);\r
+}\r
+\r
+\r
+void\r
+modexFlashOn(word fade, byte *palette) {\r
+ fadePalette(fade, -64, 64/fade+1, palette);\r
+}\r
+\r
+\r
+void\r
+modexFlashOff(word fade, byte *palette) {\r
+ fadePalette(-fade, 0, 64/fade+1, palette);\r
+}\r
+\r
+\r
+static void\r
+fadePalette(sbyte fade, sbyte start, word iter, byte *palette) {\r
+ word i;\r
+ byte dim = start;\r
+\r
+ /* handle the case where we just update */\r
+ if(iter == 0) {\r
+ modexPalUpdate(palette);\r
+ return;\r
+ }\r
+\r
+ while(iter > 0) { /* FadeLoop */\r
+ for(i=0; i<PAL_SIZE; i++) { /* loadpal_loop */\r
+ tmppal[i] = palette[i] - dim;\r
+ if(tmppal[i] > 127) {\r
+ tmppal[i] = 0;\r
+ } else if(tmppal[i] > 63) {\r
+ tmppal[i] = 63;\r
+ }\r
+ }\r
+ modexPalUpdate(tmppal);\r
+ iter--;\r
+ dim += fade;\r
+ }\r
+}\r
+\r
+\r
+/* save and load */\r
+void\r
+modexPalSave(byte *palette) {\r
+ int i;\r
+\r
+ outp(PAL_READ_REG, 0); /* start at palette entry 0 */\r
+ for(i=0; i<PAL_SIZE; i++) {\r
+ palette[i] = inp(PAL_DATA_REG); /* read the palette data */\r
+ }\r
+}\r
+\r
+\r
+byte *\r
+modexNewPal() {\r
+ byte *ptr;\r
+ ptr = malloc(PAL_SIZE);\r
+\r
+ /* handle errors */\r
+ if(!ptr) {\r
+ printf("Could not allocate palette.\n");\r
+ exit(-1);\r
+ }\r
+\r
+ return ptr;\r
+}\r
+\r
+\r
+void\r
+modexLoadPalFile(byte *filename, byte **palette) {\r
+ FILE *file;\r
+ byte *ptr;\r
+\r
+ /* free the palette if it exists */\r
+ if(*palette) {\r
+ free(*palette);\r
+ }\r
+\r
+ /* allocate the new palette */\r
+ *palette = modexNewPal();\r
+\r
+ /* open the file */\r
+ file = fopen(filename, "rb");\r
+ if(!file) {\r
+ printf("Could not open palette file: %s\n", filename);\r
+ exit(-2);\r
+ }\r
+\r
+ /* read the file */\r
+ ptr = *palette;\r
+ while(!feof(file)) {\r
+ *ptr++ = fgetc(file);\r
+ }\r
+\r
+ fclose(file);\r
+}\r
+\r
+\r
+void\r
+modexSavePalFile(char *filename, byte *pal) {\r
+ unsigned int i;\r
+ FILE *file;\r
+\r
+ /* open the file for writing */\r
+ file = fopen(filename, "wb");\r
+ if(!file) {\r
+ printf("Could not open %s for writing\n", filename);\r
+ exit(-2);\r
+ }\r
+\r
+ /* write the data to the file */\r
+ fwrite(pal, 1, PAL_SIZE, file);\r
+ fclose(file);\r
+}\r
+\r
+\r
+/* blanking */\r
+void\r
+modexPalBlack() {\r
+ fadePalette(-1, 64, 1, tmppal);\r
+}\r
+\r
+\r
+void\r
+modexPalWhite() {\r
+ fadePalette(-1, -64, 1, tmppal);\r
+}\r
+\r
+\r
+/* utility */\r
+void\r
+modexPalUpdate(byte *p) {\r
+ int i;\r
+ modexWaitBorder();\r
+ outp(PAL_WRITE_REG, 0); /* start at the beginning of palette */\r
+ for(i=0; i<PAL_SIZE/2; i++) {\r
+ outp(PAL_DATA_REG, p[i]);\r
+ }\r
+ modexWaitBorder(); /* waits one retrace -- less flicker */\r
+ for(i=PAL_SIZE/2; i<PAL_SIZE; i++) {\r
+ outp(PAL_DATA_REG, p[i]);\r
+ }\r
+}\r
+\r
+\r
+void\r
+modexWaitBorder() {\r
+ while(inp(INPUT_STATUS_1) & 8) {\r
+ /* spin */\r
+ }\r
+\r
+ while(!(inp(INPUT_STATUS_1) & 8)) {\r
+ /* spin */\r
+ }\r
+}\r
+\r
+\r
+bitmap_t\r
+modexLoadPcx(char *filename) {\r
+ FILE *file;\r
+ bitmap_t result;\r
+ struct pcxHeader head;\r
+ long bufSize;\r
+ int index;\r
+ byte count, val;\r
+\r
+ /* open the PCX file for reading */\r
+ file = fopen(filename, "rb");\r
+ if(!file) {\r
+ printf("Could not open %s for reading.\n", filename);\r
+ exit(-2);\r
+ }\r
+\r
+ /* read the header */\r
+ fread(&head, sizeof(char), sizeof(struct pcxHeader), file);\r
+\r
+ /* make sure this is 8bpp */\r
+ if(head.bpp != 8) {\r
+ printf("I only know how to handle 8bpp pcx files!\n");\r
+ fclose(file);\r
+ exit(-2);\r
+ }\r
+\r
+ /* allocate the buffer */\r
+ result.width = head.xmax - head.xmin + 1;\r
+ result.height = head.ymax - head.ymin + 1;\r
+ bufSize = result.width * result.height;\r
+ result.data = malloc(bufSize);\r
+ if(!result.data) {\r
+ printf("Could not allocate memory for bitmap data.");\r
+ fclose(file);\r
+ exit(-1);\r
+ }\r
+\r
+ /* read the buffer in */\r
+ index = 0;\r
+ do {\r
+ /* get the run length and the value */\r
+ count = fgetc(file);\r
+ if(0xC0 == (count & 0xC0)) { /* this is the run count */\r
+ count &= 0x3f;\r
+ val = fgetc(file);\r
+ } else {\r
+ val = count;\r
+ count = 1;\r
+ }\r
+\r
+ /* write the pixel the specified number of times */\r
+ for(; count && index < bufSize; count--,index++) {\r
+ result.data[index] = val;\r
+ }\r
+ } while(index < bufSize);\r
+\r
+ /* handle the palette */\r
+ fseek(file, -769, SEEK_END);\r
+ val = fgetc(file);\r
+ result.palette = modexNewPal();\r
+ if(head.version == 5 && val == 12) {\r
+ /* use the vga palette */\r
+ for(index=0; !feof(file) && index < PAL_SIZE; index++) {\r
+ val = fgetc(file);\r
+ result.palette[index] = val >> 2;\r
+ }\r
+ } else {\r
+ /* use the 16 color palette */\r
+ for(index=0; index<48; index++) {\r
+ result.palette[index] = head.pal16[index];\r
+ }\r
+ }\r
+\r
+ fclose(file);\r
+\r
+ return result;\r
+}\r