]> 4ch.mooo.com Git - 16.git/blob - src/lib/modex/demos/basic7/utils.asm
16_ca needs huge amounts of work and I should remember what needs to be done soon...
[16.git] / src / lib / modex / demos / basic7 / utils.asm
1 ;=======================================================\r
2 ;===  UTILS.ASM  - Asm Utilities for QuickBasic/BC7  ===\r
3 ;=======================================================\r
4 \r
5         PAGE    255, 132\r
6 \r
7         .MODEL Medium\r
8         .286\r
9 \r
10         ; ==== MACROS ====\r
11 \r
12         ; macros to PUSH and POP multiple registers\r
13 \r
14 PUSHx MACRO R1, R2, R3, R4, R5, R6, R7, R8\r
15         IFNB <R1>\r
16                 push    R1                              ; Save R1\r
17                 PUSHx   R2, R3, R4, R5, R6, R7, R8\r
18         ENDIF\r
19 ENDM\r
20 \r
21 POPx MACRO R1, R2, R3, R4, R5, R6, R7, R8\r
22         IFNB <R1>\r
23                 pop             R1                              ; Restore R1\r
24                 POPx    R2, R3, R4, R5, R6, R7, R8\r
25         ENDIF\r
26 ENDM\r
27 \r
28         ; Macro to Clear a Register to 0\r
29 \r
30 CLR MACRO Register\r
31         xor             Register, Register              ; Set Register = 0\r
32 ENDM\r
33 \r
34         ; Macros to Decrement Counter & Jump on Condition\r
35 \r
36 LOOPx MACRO Register, Destination\r
37         dec             Register                                ; Counter--\r
38         jnz             Destination                             ; Jump if not 0\r
39 ENDM\r
40 \r
41 LOOPjz MACRO Register, Destination\r
42         dec             Register                                ; Counter--\r
43         jz              Destination                             ; Jump if 0\r
44 ENDM\r
45 \r
46 \r
47         ; ==== General Constants ====\r
48 \r
49         False   EQU     0\r
50         True    EQU     -1\r
51         nil             EQU 0\r
52 \r
53         b               EQU     BYTE PTR\r
54         w               EQU     WORD PTR\r
55         d               EQU     DWORD PTR\r
56         o               EQU     OFFSET\r
57         f               EQU FAR PTR\r
58         s               EQU     SHORT\r
59         ?x4             EQU <?,?,?,?>\r
60         ?x3             EQU <?,?,?>\r
61 \r
62 \r
63 IFDEF FARSTRINGS\r
64 \r
65         EXTRN   stringaddress:far\r
66         EXTRN   stringlength:far\r
67 \r
68 ENDIF\r
69 \r
70 \r
71         .Data\r
72 \r
73         EVEN\r
74 \r
75 RND_Seed        DW      7397, 29447, 802\r
76 RND_Mult        DW      179, 183, 182\r
77 RND_ModV        DW      32771, 32779, 32783\r
78 \r
79 CR_LF           DB      13, 10                  ; the CRLF data\r
80 \r
81         .Code\r
82 \r
83 ;=================\r
84 ;DOS_PRINT (Text$)\r
85 ;=================\r
86 ;\r
87 ; Prints Text Directly to DOS console w/ CR/LF\r
88 ;\r
89 \r
90         PUBLIC  DOS_PRINT\r
91 \r
92 DP_Stack        STRUC\r
93                                 DW      ?x4     ; DI, SI, DS, BP\r
94                                 DD      ?       ; Caller\r
95         DP_Text         DW      ?       ; Address of Text$ Descriptor\r
96 DP_Stack        ENDS\r
97 \r
98 \r
99 DOS_PRINT        PROC    FAR\r
100 \r
101         PUSHx   BP, DS, SI, DI          ; Preserve Important Registers\r
102         mov             BP, SP                          ; Set up Stack Frame\r
103 \r
104         mov     SI, [BP].DP_Text                ; Get Addr of Text$ descriptor\r
105 \r
106 IFDEF FARSTRINGS\r
107         push    SI                                      ; Push Addr of BC7 Decriptor Ptr\r
108         call    stringaddress           ; Get Address + Len of string!!!\r
109                                                                 ; DX:AX = Addr  CX = Len\r
110         mov             DS, DX                          ; DS = DX = Segment of string\r
111         mov             DX, AX                          ; DX = AX = Offset of String\r
112 ELSE\r
113         mov     CX, [SI]                ; put its length into CX\r
114     mov     DX, [SI+02]         ; now DS:DX points to the String\r
115 ENDIF\r
116 \r
117         jcxz    @No_Print                       ; Don't Print if empty\r
118 \r
119         mov             BX, 1                           ; 1= DOS Handle for Display\r
120         mov             AH, 40h                         ; Write Text Function\r
121         int             21h                                     ; Call DOS to do it\r
122 \r
123 @No_Print:\r
124         mov             AX, SEG DGROUP          ; Restore DGroup\r
125         mov             DS, AX\r
126 \r
127         mov             DX, o CR_LF                     ; Get Addr of CR/LF pair\r
128         mov             CX, 2                           ; 2 Characters to Write         \r
129         mov             BX, 1                           ; 1= DOS Handle for Display\r
130 \r
131         mov             AH, 40h                         ; Write Text Function\r
132         int             21h                                     ; Call DOS to do it\r
133 \r
134         cld                                                     ; Reset Direction Flag          \r
135         POPx    DI, SI, DS, BP          ; Restore Saved Registers\r
136         ret             2                                       ; Exit & Clean Up Stack\r
137 \r
138 DOS_PRINT        ENDP\r
139 \r
140 \r
141 ;==================\r
142 ;DOS_PRINTS (Text$)\r
143 ;==================\r
144\r
145 ; Print Text$ Directly to DOS console \r
146 ; without a trailing CR/LF\r
147 ;\r
148 \r
149         PUBLIC  DOS_PRINTS\r
150 \r
151 DOS_PRINTS       PROC    FAR\r
152 \r
153         PUSHx   BP, DS, SI, DI          ; Preserve Important Registers\r
154         mov             BP, SP                          ; Set up Stack Frame\r
155 \r
156     mov     SI, [BP].DP_Text    ; Get Addr of Text$ descriptor\r
157 \r
158 IFDEF FARSTRINGS\r
159         push    SI                                      ; Push Addr of BC7 Decriptor Ptr\r
160         call    stringaddress           ; Get Address + Len of string!!!\r
161                                                                 ; DX:AX = Addr  CX = Len\r
162         mov             DS, DX                          ; DS = DX = Segment of string\r
163         mov             DX, AX                          ; DX = AX = Offset of String\r
164 ELSE\r
165         mov     CX, [SI]                ; put its length into CX\r
166     mov     DX, [SI+02]         ; now DS:DX points to the String\r
167 ENDIF\r
168 \r
169         jcxz    @DPS_Exit                       ; Don't Print if empty\r
170 \r
171         mov             BX, 1                           ; 1= DOS Handle for Display\r
172         mov             AH, 40h                         ; Write Text Function\r
173         int             21h                                     ; Call DOS to do it\r
174 \r
175 @DPS_Exit:\r
176         cld                                                     ; Reset Direction Flag          \r
177         POPx    DI, SI, DS, BP          ; Restore Saved Registers\r
178         ret             2                                       ; Exit & Clean Up Stack\r
179 \r
180 DOS_PRINTS       ENDP\r
181 \r
182 \r
183 ;======================\r
184 ;SET_VIDEO_MODE (Mode%) \r
185 ;======================\r
186 ;\r
187 ; Sets the Video Mode through the BIOS\r
188 ;\r
189 \r
190         PUBLIC  SET_VIDEO_MODE\r
191 \r
192 SVM_Stack       STRUC\r
193                                 DW      ?x4     ; DI, SI, DS, BP\r
194                                 DD      ?       ; Caller\r
195         SVM_Mode        DB      ?,? ; Desired Video Mode\r
196 SVM_Stack       ENDS\r
197 \r
198 \r
199 SET_VIDEO_MODE  PROC    FAR\r
200 \r
201         PUSHx   BP, DS, SI, DI          ; Preserve Important Registers\r
202         mov             BP, SP                          ; Set up Stack Frame\r
203 \r
204         CLR             AH                                      ; Function 0\r
205         mov             AL, [BP].SVM_Mode       ; Get Mode #\r
206 \r
207         int             10H                                     ; Change Video Modes\r
208 \r
209 @SVM_Exit:\r
210         POPx    DI, SI, DS, BP          ; Restore Saved Registers\r
211         ret             2                                       ; Exit & Clean Up Stack\r
212 \r
213 SET_VIDEO_MODE  ENDP\r
214 \r
215 \r
216 ;==============\r
217 ;SCAN_KEYBOARD%\r
218 ;==============\r
219 ;\r
220 ; Function to scan keyboard for a pressed key\r
221 ;\r
222 \r
223         PUBLIC  SCAN_KEYBOARD\r
224 \r
225 SCAN_KEYBOARD   PROC    FAR\r
226 \r
227         PUSHx   BP, DS, SI, DI          ; Preserve Important Registers\r
228 \r
229         mov             AH, 01H                         ; Function #1\r
230         int             16H                                     ; Call Keyboard Driver\r
231         jz              @SK_NO_KEY                      ; Exit if Zero flag set\r
232 \r
233         mov             AH,     00H                             ; Remove Key from Buffer\r
234         int             16H                                     ; Get Keycode in AX\r
235 \r
236         or              AL, AL                          ; Low Byte Set (Ascii?)\r
237         jz              @SK_Exit                        ; if not, it's a F-Key\r
238 \r
239         CLR             AH                                      ; Clear ScanCode if Ascii\r
240         jmp             s @SK_Exit                      ; Return Key in AX\r
241 \r
242 @SK_NO_KEY:\r
243         CLR             AX                                      ; Return Nil (no Keypress)\r
244 \r
245 @SK_Exit:\r
246         cld                                                     ; Reset Direction Flag          \r
247         POPx    DI, SI, DS, BP          ; Restore Saved Registers\r
248         ret                                                     ; Exit & Clean Up Stack\r
249 \r
250 SCAN_KEYBOARD   ENDP\r
251 \r
252 \r
253 ;====================\r
254 ;RANDOM_INT (MaxInt%)\r
255 ;====================\r
256 ;\r
257 ; Returns a pseudo-random number in the range of (0.. MaxInt-1)\r
258 ;\r
259 \r
260 \r
261         PUBLIC  RANDOM_INT\r
262 \r
263 RI_Stack        STRUC\r
264                                 DW      ?       ; BP\r
265                                 DD      ?       ; Caller\r
266         RI_MaxVal       DW      ?       ; Maximum Value to Return + 1\r
267 RI_Stack        ENDS\r
268 \r
269 \r
270 RANDOM_INT      PROC    FAR\r
271 \r
272         push    BP                                      ; Preserve Important Registers\r
273         mov             BP, SP                          ; Set up Stack Frame\r
274 \r
275         CLR             BX                                      ; BX is the data index\r
276         CLR             CX                              ; CX is the accumulator\r
277 \r
278 REPT 3\r
279         mov             AX, RND_Seed[BX]        ; load the initial seed\r
280         mul             RND_Mult[BX]            ; multiply it\r
281         div             RND_ModV[BX]            ; and obtain the Mod value\r
282         mov             RND_Seed[BX], DX        ; save that for the next time\r
283 \r
284         add             CX, DX                          ; add it into the accumulator\r
285         inc             BX\r
286         inc             BX                      ; point to the next set of values\r
287 ENDM\r
288 \r
289         mov             AX, CX                          ; AX = Random #\r
290         CLR             DX                                      ; DX = 0\r
291         div             [BP].RI_MaxVal          ; DX = DX:AX / MAxVal Remainder\r
292 \r
293         mov             AX, DX\r
294 \r
295         pop             BP                                      ; Restore BP\r
296         ret             2                               ; back to BASIC with AX holding the result\r
297 \r
298 RANDOM_INT      ENDP\r
299 \r
300 \r
301 ;===========\r
302 ;INIT_RANDOM\r
303 ;===========\r
304 ;\r
305 ; Scrambles the psuedo-random number sequence\r
306 ; (XOR's the seed value with the timer)\r
307 ;\r
308 \r
309         PUBLIC  INIT_RANDOM\r
310 \r
311 INIT_RANDOM     PROC    FAR\r
312 \r
313         clr             AX                                      ; Segment = 0000\r
314         mov             ES, AX\r
315         mov             AX, ES:[046Ch]      ; Get Timer Lo Word\r
316 \r
317         xor             RND_Seed, AX            ; Scramble 1st Seed\r
318 \r
319         ret                                                     ; Exit & Clean Up Stack\r
320 \r
321 INIT_RANDOM     ENDP\r
322 \r
323 \r
324 ;====================\r
325 ;INT_SQR (X%, Round%)\r
326 ;====================\r
327 ;\r
328 ; Returns the Integer Square Root of (X)\r
329 ; Round allows the return value to be rounded to the \r
330 ; nearest integer value by passing 0x80.  Passing 0\r
331 ; return the Integer Portion only.  The rounding amound is\r
332 ; a number from 0 to 1 multiplied by 256, thus \r
333 ; 0.5 * 0x100 = 0x80!\r
334 ;\r
335 \r
336 ISQ_Stack       STRUC\r
337                                         DW      ?,?     ; BP, DI\r
338                                         DD      ?       ; Caller\r
339         ISQ_Round               DW      ?       ; Amount to Round Result * 256\r
340         ISQ_X                   DW      ?       ; "X"\r
341 ISQ_Stack       ENDS\r
342 \r
343         PUBLIC  INT_SQR\r
344 \r
345 INT_SQR         PROC    FAR\r
346 \r
347     PUSHx   BP, DI                              ; Save BP\r
348     mov     BP, SP                              ; Set up Stack Frame\r
349 \r
350         xor     AX, AX                          ; {xor eax,eax}\r
351         xor     DX, DX                          ; {xor edx,edx}\r
352         mov     DI, [BP].ISQ_X          ; {mov edi,x}\r
353 \r
354         mov     CX, 16                          ; {mov cx, 32}\r
355 \r
356 @ISQ_L:\r
357 \r
358         shl     DI, 1                           ; {shl edi,1}\r
359         rcl     DX, 1                           ; {rcl edx,1}\r
360         shl     DI, 1                           ; {shl edi,1}\r
361         rcl     DX, 1                           ; {rcl edx,1}\r
362         shl     AX, 1                           ; {shl eax,1}\r
363         mov     BX, AX                          ; {mov ebx,eax}\r
364         shl     BX, 1                           ; {shl ebx,1}\r
365         inc     BX                                      ; {inc ebx}\r
366         cmp     DX, BX                          ; {cmp edx,ebx}\r
367         jl              @ISQ_S\r
368 \r
369         sub     DX, BX                          ; {sub edx,ebx}\r
370         inc     AX                                      ; {inc eax}\r
371 \r
372 @ISQ_S: \r
373         loop    @ISQ_L\r
374 \r
375         add     ax, [BP].ISQ_Round      ; {add eax,$00008000}  \r
376                                                                 ; {*round* result in hi word: ie. +0.5}\r
377         shr     ax, 8                           ; {shr eax,16}  {to ax (result)}\r
378 \r
379         POPx    DI, BP                          ; Restore Registers     \r
380         ret             4                                       ; Exit\r
381 \r
382 INT_SQR         ENDP\r
383 \r
384 \r
385 ;============\r
386 ;TIMER_COUNT&\r
387 ;============\r
388 ;\r
389 ; Returns the current timer value as an integer/long integer\r
390 ;\r
391 \r
392 \r
393         PUBLIC  TIMER_COUNT\r
394 \r
395 TIMER_COUNT      PROC    FAR\r
396 \r
397         clr             AX                                      ; Segment = 0000\r
398         mov             ES, AX                          ; use ES to get at data\r
399         mov             AX, ES:[046Ch]      ; Get Timer Lo Word\r
400         mov             DX, ES:[046Eh]          ; Get Timer Hi Word\r
401         ret                                                     ; Exit & Return value in DX:AX\r
402 \r
403 TIMER_COUNT      ENDP\r
404 \r
405 \r
406         END\r