]> 4ch.mooo.com Git - 16.git/blobdiff - src/lib/modex/demos/qb45/utils.asm
wwww
[16.git] / src / lib / modex / demos / qb45 / utils.asm
diff --git a/src/lib/modex/demos/qb45/utils.asm b/src/lib/modex/demos/qb45/utils.asm
new file mode 100755 (executable)
index 0000000..811b8f8
--- /dev/null
@@ -0,0 +1,406 @@
+;=======================================================\r
+;===  UTILS.ASM  - Asm Utilities for QuickBasic/BC7  ===\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
+       False   EQU     0\r
+       True    EQU     -1\r
+       nil             EQU 0\r
+\r
+       b               EQU     BYTE PTR\r
+       w               EQU     WORD PTR\r
+       d               EQU     DWORD PTR\r
+       o               EQU     OFFSET\r
+       f               EQU FAR PTR\r
+       s               EQU     SHORT\r
+       ?x4             EQU <?,?,?,?>\r
+       ?x3             EQU <?,?,?>\r
+\r
+\r
+IFDEF FARSTRINGS\r
+\r
+       EXTRN   stringaddress:far\r
+       EXTRN   stringlength:far\r
+\r
+ENDIF\r
+\r
+\r
+       .Data\r
+\r
+       EVEN\r
+\r
+RND_Seed       DW      7397, 29447, 802\r
+RND_Mult       DW      179, 183, 182\r
+RND_ModV       DW      32771, 32779, 32783\r
+\r
+CR_LF          DB      13, 10                  ; the CRLF data\r
+\r
+       .Code\r
+\r
+;=================\r
+;DOS_PRINT (Text$)\r
+;=================\r
+;\r
+; Prints Text Directly to DOS console w/ CR/LF\r
+;\r
+\r
+       PUBLIC  DOS_PRINT\r
+\r
+DP_Stack       STRUC\r
+                               DW      ?x4     ; DI, SI, DS, BP\r
+                               DD      ?       ; Caller\r
+       DP_Text         DW      ?       ; Address of Text$ Descriptor\r
+DP_Stack       ENDS\r
+\r
+\r
+DOS_PRINT       PROC    FAR\r
+\r
+       PUSHx   BP, DS, SI, DI          ; Preserve Important Registers\r
+       mov             BP, SP                          ; Set up Stack Frame\r
+\r
+       mov     SI, [BP].DP_Text                ; Get Addr of Text$ descriptor\r
+\r
+IFDEF FARSTRINGS\r
+       push    SI                                      ; Push Addr of BC7 Decriptor Ptr\r
+       call    stringaddress           ; Get Address + Len of string!!!\r
+                                                               ; DX:AX = Addr  CX = Len\r
+       mov             DS, DX                          ; DS = DX = Segment of string\r
+       mov             DX, AX                          ; DX = AX = Offset of String\r
+ELSE\r
+       mov     CX, [SI]                ; put its length into CX\r
+    mov     DX, [SI+02]        ; now DS:DX points to the String\r
+ENDIF\r
+\r
+       jcxz    @No_Print                       ; Don't Print if empty\r
+\r
+       mov             BX, 1                           ; 1= DOS Handle for Display\r
+       mov             AH, 40h                         ; Write Text Function\r
+       int             21h                                     ; Call DOS to do it\r
+\r
+@No_Print:\r
+       mov             AX, SEG DGROUP          ; Restore DGroup\r
+       mov             DS, AX\r
+\r
+       mov             DX, o CR_LF                     ; Get Addr of CR/LF pair\r
+       mov             CX, 2                           ; 2 Characters to Write         \r
+       mov             BX, 1                           ; 1= DOS Handle for Display\r
+\r
+       mov             AH, 40h                         ; Write Text Function\r
+       int             21h                                     ; Call DOS to do it\r
+\r
+       cld                                                     ; Reset Direction Flag          \r
+       POPx    DI, SI, DS, BP          ; Restore Saved Registers\r
+       ret             2                                       ; Exit & Clean Up Stack\r
+\r
+DOS_PRINT       ENDP\r
+\r
+\r
+;==================\r
+;DOS_PRINTS (Text$)\r
+;==================\r
+; \r
+; Print Text$ Directly to DOS console \r
+; without a trailing CR/LF\r
+;\r
+\r
+       PUBLIC  DOS_PRINTS\r
+\r
+DOS_PRINTS      PROC    FAR\r
+\r
+       PUSHx   BP, DS, SI, DI          ; Preserve Important Registers\r
+       mov             BP, SP                          ; Set up Stack Frame\r
+\r
+    mov     SI, [BP].DP_Text   ; Get Addr of Text$ descriptor\r
+\r
+IFDEF FARSTRINGS\r
+       push    SI                                      ; Push Addr of BC7 Decriptor Ptr\r
+       call    stringaddress           ; Get Address + Len of string!!!\r
+                                                               ; DX:AX = Addr  CX = Len\r
+       mov             DS, DX                          ; DS = DX = Segment of string\r
+       mov             DX, AX                          ; DX = AX = Offset of String\r
+ELSE\r
+       mov     CX, [SI]                ; put its length into CX\r
+    mov     DX, [SI+02]        ; now DS:DX points to the String\r
+ENDIF\r
+\r
+       jcxz    @DPS_Exit                       ; Don't Print if empty\r
+\r
+       mov             BX, 1                           ; 1= DOS Handle for Display\r
+       mov             AH, 40h                         ; Write Text Function\r
+       int             21h                                     ; Call DOS to do it\r
+\r
+@DPS_Exit:\r
+       cld                                                     ; Reset Direction Flag          \r
+       POPx    DI, SI, DS, BP          ; Restore Saved Registers\r
+       ret             2                                       ; Exit & Clean Up Stack\r
+\r
+DOS_PRINTS      ENDP\r
+\r
+\r
+;======================\r
+;SET_VIDEO_MODE (Mode%) \r
+;======================\r
+;\r
+; Sets the Video Mode through the BIOS\r
+;\r
+\r
+       PUBLIC  SET_VIDEO_MODE\r
+\r
+SVM_Stack      STRUC\r
+                               DW      ?x4     ; DI, SI, DS, BP\r
+                               DD      ?       ; Caller\r
+       SVM_Mode        DB      ?,? ; Desired Video Mode\r
+SVM_Stack      ENDS\r
+\r
+\r
+SET_VIDEO_MODE PROC    FAR\r
+\r
+       PUSHx   BP, DS, SI, DI          ; Preserve Important Registers\r
+       mov             BP, SP                          ; Set up Stack Frame\r
+\r
+       CLR             AH                                      ; Function 0\r
+       mov             AL, [BP].SVM_Mode       ; Get Mode #\r
+\r
+       int             10H                                     ; Change Video Modes\r
+\r
+@SVM_Exit:\r
+       POPx    DI, SI, DS, BP          ; Restore Saved Registers\r
+       ret             2                                       ; Exit & Clean Up Stack\r
+\r
+SET_VIDEO_MODE ENDP\r
+\r
+\r
+;==============\r
+;SCAN_KEYBOARD%\r
+;==============\r
+;\r
+; Function to scan keyboard for a pressed key\r
+;\r
+\r
+       PUBLIC  SCAN_KEYBOARD\r
+\r
+SCAN_KEYBOARD  PROC    FAR\r
+\r
+       PUSHx   BP, DS, SI, DI          ; Preserve Important Registers\r
+\r
+       mov             AH, 01H                         ; Function #1\r
+       int             16H                                     ; Call Keyboard Driver\r
+       jz              @SK_NO_KEY                      ; Exit if Zero flag set\r
+\r
+       mov             AH,     00H                             ; Remove Key from Buffer\r
+       int             16H                                     ; Get Keycode in AX\r
+\r
+       or              AL, AL                          ; Low Byte Set (Ascii?)\r
+       jz              @SK_Exit                        ; if not, it's a F-Key\r
+\r
+       CLR             AH                                      ; Clear ScanCode if Ascii\r
+       jmp             s @SK_Exit                      ; Return Key in AX\r
+\r
+@SK_NO_KEY:\r
+       CLR             AX                                      ; Return Nil (no Keypress)\r
+\r
+@SK_Exit:\r
+       cld                                                     ; Reset Direction Flag          \r
+       POPx    DI, SI, DS, BP          ; Restore Saved Registers\r
+       ret                                                     ; Exit & Clean Up Stack\r
+\r
+SCAN_KEYBOARD  ENDP\r
+\r
+\r
+;====================\r
+;RANDOM_INT (MaxInt%)\r
+;====================\r
+;\r
+; Returns a pseudo-random number in the range of (0.. MaxInt-1)\r
+;\r
+\r
+\r
+       PUBLIC  RANDOM_INT\r
+\r
+RI_Stack       STRUC\r
+                               DW      ?       ; BP\r
+                               DD      ?       ; Caller\r
+       RI_MaxVal       DW      ?       ; Maximum Value to Return + 1\r
+RI_Stack       ENDS\r
+\r
+\r
+RANDOM_INT     PROC    FAR\r
+\r
+       push    BP                                      ; Preserve Important Registers\r
+       mov             BP, SP                          ; Set up Stack Frame\r
+\r
+       CLR             BX                                      ; BX is the data index\r
+       CLR             CX                              ; CX is the accumulator\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
+\r
+       mov             AX, CX                          ; AX = Random #\r
+       CLR             DX                                      ; DX = 0\r
+       div             [BP].RI_MaxVal          ; DX = DX:AX / MAxVal Remainder\r
+\r
+       mov             AX, DX\r
+\r
+       pop             BP                                      ; Restore BP\r
+       ret             2                               ; back to BASIC with AX holding the result\r
+\r
+RANDOM_INT     ENDP\r
+\r
+\r
+;===========\r
+;INIT_RANDOM\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
+INIT_RANDOM    PROC    FAR\r
+\r
+       clr             AX                                      ; Segment = 0000\r
+       mov             ES, AX\r
+       mov             AX, ES:[046Ch]      ; Get Timer Lo Word\r
+\r
+       xor             RND_Seed, AX            ; Scramble 1st Seed\r
+\r
+       ret                                                     ; Exit & Clean Up Stack\r
+\r
+INIT_RANDOM    ENDP\r
+\r
+\r
+;====================\r
+;INT_SQR (X%, 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
+ISQ_Stack      STRUC\r
+                                       DW      ?,?     ; BP, DI\r
+                                       DD      ?       ; Caller\r
+       ISQ_Round               DW      ?       ; Amount to Round Result * 256\r
+       ISQ_X                   DW      ?       ; "X"\r
+ISQ_Stack      ENDS\r
+\r
+       PUBLIC  INT_SQR\r
+\r
+INT_SQR                PROC    FAR\r
+\r
+    PUSHx   BP, DI                             ; Save BP\r
+    mov     BP, SP                             ; Set up Stack Frame\r
+\r
+       xor     AX, AX                          ; {xor eax,eax}\r
+       xor     DX, DX                          ; {xor edx,edx}\r
+       mov     DI, [BP].ISQ_X          ; {mov edi,x}\r
+\r
+       mov     CX, 16                          ; {mov cx, 32}\r
+\r
+@ISQ_L:\r
+\r
+       shl     DI, 1                           ; {shl edi,1}\r
+       rcl     DX, 1                           ; {rcl edx,1}\r
+       shl     DI, 1                           ; {shl edi,1}\r
+       rcl     DX, 1                           ; {rcl edx,1}\r
+       shl     AX, 1                           ; {shl eax,1}\r
+       mov     BX, AX                          ; {mov ebx,eax}\r
+       shl     BX, 1                           ; {shl ebx,1}\r
+       inc     BX                                      ; {inc ebx}\r
+       cmp     DX, BX                          ; {cmp edx,ebx}\r
+       jl              @ISQ_S\r
+\r
+       sub     DX, BX                          ; {sub edx,ebx}\r
+       inc     AX                                      ; {inc eax}\r
+\r
+@ISQ_S: \r
+       loop    @ISQ_L\r
+\r
+       add     ax, [BP].ISQ_Round      ; {add eax,$00008000}  \r
+                                                               ; {*round* result in hi word: ie. +0.5}\r
+       shr     ax, 8                           ; {shr eax,16}  {to ax (result)}\r
+\r
+       POPx    DI, BP                          ; Restore Registers     \r
+       ret             4                                       ; Exit\r
+\r
+INT_SQR                ENDP\r
+\r
+\r
+;============\r
+;TIMER_COUNT&\r
+;============\r
+;\r
+; Returns the current timer value as an integer/long integer\r
+;\r
+\r
+\r
+       PUBLIC  TIMER_COUNT\r
+\r
+TIMER_COUNT      PROC    FAR\r
+\r
+       clr             AX                                      ; Segment = 0000\r
+       mov             ES, AX                          ; use ES to get at data\r
+       mov             AX, ES:[046Ch]      ; Get Timer Lo Word\r
+       mov             DX, ES:[046Eh]          ; Get Timer Hi Word\r
+       ret                                                     ; Exit & Return value in DX:AX\r
+\r
+TIMER_COUNT      ENDP\r
+\r
+\r
+       END\r