]> 4ch.mooo.com Git - 16.git/blob - 16/scrasm/INIT.INC
16_ca needs huge amounts of work and I should remember what needs to be done soon...
[16.git] / 16 / scrasm / INIT.INC
1 ;; Error messages\r
2 ERR_OK          EQU     0\r
3 msgErr0         db      'Later!',13,10,'$'\r
4 ERR_MEM         EQU     1\r
5 msgErr1         db      'Error 001:  Out of memory?',13,10,'$'\r
6 ERR_CPU         EQU     2\r
7 msgErr2         db      'Error 002:  CPU must be at least an 80386.',13,10,'$'\r
8 ERR_FILE        EQU     3\r
9 msgErr3         db      'Error 003:  File error.',13,10,'$'\r
10 ERR_FILENOTFOUND EQU    4\r
11 msgErr4         db      'Error 004:  File not found.',13,10,'$'\r
12 msgtblError     dw      offset msgErr0, offset msgErr1, offset msgErr2,\r
13                         offset msgErr3, offset msgErr4\r
14 nError          db      0\r
15 \r
16 ;; CPU name strings\r
17 CPUName86       DB      "8088/8086$"\r
18 CPUName286      DB      "80286DX/SX$"\r
19 CPUName386      DB      "80386DX/SX$"\r
20 CPUName486      DB      "80486DX/SX or better$"\r
21 CPUNameTable    DW      CPUName86,CPUName286,CPUName386,CPUName486\r
22 \r
23 EVEN\r
24 msgCPUTypeIs    DB      "Your CPU type:  $"\r
25 EVEN\r
26 msgCPUTypeIsEnd DB      13,10,'$'\r
27 nCPU            DB      0\r
28 \r
29 EVEN\r
30 msgPages        DB      'Pages displayed:  '\r
31 strNumPages     DB      6 dup (?),13,10,'$'\r
32 \r
33 EVEN\r
34 bufText         DW      80*50 DUP (?)   ; Needs this much to hold\r
35                                         ; a 50-line screen...\r
36 wCPos           DW      0\r
37 nDisplay        DB      0\r
38 \r
39 EVEN\r
40 fnMap1          db      'DIAGONAL.MAP',0\r
41 fnTiles1        db      'DIAGONAL.TIL',0\r
42 fnPalette       db      'DIAGONAL.PAL',0        ; only one allowed, for now\r
43 fnMap2          db      'SCROLL.MAP',0\r
44 fnTiles2        db      'SCROLL.TIL',0\r
45 \r
46 fntblMap        dw      offset fnMap1,offset fnMap2\r
47 fntblTiles      dw      offset fnTiles1,offset fnTiles2\r
48 nMap            dw      0\r
49 \r
50 ;; CPUType routine snatched from Ray Duncan's _Power Programming MASM_\r
51 ;; chapter 14.  Reformatted to my style, but I left the code alone\r
52 ;; except that it used to push a bunch of stuff, but doesn't any more\r
53 ;; because I don't care what gets destroyed.\r
54 CPUType         PROC    near\r
55                 pushf                   ; now try to clear bits 12-15\r
56                 pop     ax              ; of CPU flags\r
57                 and     ax,0fffh\r
58                 push    ax              ; set modified CPU flags\r
59                 popf\r
60                 pushf\r
61                 pop     ax              ; get flags again\r
62                 and     ax,0f000h       ; if bits 12-15 are still\r
63                 cmp     ax,0f000h       ; set, this is 8086/88\r
64                 jne     cpu1            ; jump, not 8086/88\r
65                 mov     nCPU,CPU8086    ; set nCPU = 86/88 CPU type\r
66                 jmp     cpux            ; and exit\r
67 \r
68 cpu1:           or      ax,0f000h       ; must be 286 or later,\r
69                 push    ax              ; now try to set bits 12-15\r
70                 popf                    ; of CPU flags\r
71                 pushf\r
72                 pop     ax              ; if bits 12-15 can't be\r
73                 and     ax,0f000h       ; set, this is a 286\r
74                 jnz     cpu2            ; jump, not 80286\r
75                 mov     nCPU,CPU80286   ; set nCPU = 286 CPU type\r
76                 jmp     cpux            ; and exit\r
77 \r
78 cpu2:           mov     bx,sp           ; 386 or later, save SP\r
79                 and     sp,not 3        ; avoid stack alignment fault\r
80                 pushfd                  ; get value of EFLAGS\r
81                 pop     eax\r
82                 mov     ecx,eax         ; save copy of EFLAGS\r
83                 xor     eax,40000h      ; flip AC bit in EFLAGS\r
84                 push    eax             ; try and force EFLAGS\r
85                 popfd\r
86                 pushfd                  ; get back EFLAGS value\r
87                 pop     eax\r
88                 mov     sp,bx           ; restore old stack pointer\r
89                 xor     eax,ecx         ; can AC bit be changed?\r
90                 jnz     cpu3            ; no, jump, not a 386\r
91                 mov     nCPU,CPU80386   ; set nCPU = 386 CPU type\r
92                 jmp     cpux            ; and exit\r
93 \r
94 cpu3:           mov     nCPU,CPU80486   ; set nCPU = 486 CPU type\r
95 \r
96 cpux:           mov     bl,nCPU\r
97                 xor     bh,bh\r
98                 shl     bx,1\r
99                 DOSPRINT <offset msgCPUTypeIs>\r
100                 DOSPRINT CPUNameTable[bx]\r
101                 DOSPRINT <offset msgCPUTypeIsEnd>\r
102                 ret                     ; return with nCPU = CPU type\r
103 CPUType         ENDP\r
104 \r
105 ;; Initialize:  So far, all it does is make sure you have a 386 +\r
106 ;; (because that's what I assembled the code for).\r
107 Initialize      PROC    near\r
108         ; Set DS = CS in this program, since data is local\r
109                 mov     ax,cs\r
110                 mov     segCode,ax      ; Store the Code Segment\r
111                 mov     bx,ds\r
112                 mov     segPSP,bx       ; Store the PSP Segment\r
113                 mov     ds,ax           ; Set DS = CS\r
114 \r
115         ; Resize code to 64K\r
116         CODE_SIZE EQU 64                ; <- this is arbitrary.\r
117                 ; ES already -> allocated segment\r
118                 mov     ah,4ah\r
119                 mov     bx,64*CODE_SIZE\r
120                 int     21h\r
121                 mov     nError,ERR_MEM\r
122                 jc      TerminateError\r
123 \r
124 ;; I've chosen not to implement sprites yet so that I can get this out\r
125 ;; the door...\r
126 ;; ; 320x200 buffer for sprite drawing.  To draw sprites, first draw them\r
127 ;; ; into this buffer, adding rectangles to the current rectangle list.\r
128 ;; ; Then, use BUFFER_COPY to put out the buffers with the current\r
129 ;; ; rectangle list to the screen.  BUFFER_COPY will ensure minimal VGA\r
130 ;; ; writing.\r
131 ;;         ; Create a buffer segment\r
132 ;;                 mov     bx,(320 * 200) / 16\r
133 ;;                 mov     ah,48h\r
134 ;;                 int     21h\r
135 ;;                 mov     nError,ERR_MEM\r
136 ;;                 jc      TerminateError\r
137 ;;                 mov     segBuffer,ax\r
138 \r
139                 call    CPUType\r
140                 mov     nError,ERR_CPU\r
141                 cmp     nCPU,2\r
142                 jl      TerminateError\r
143 \r
144                 mov     ds,segCode\r
145                 mov     dx,offset fnPalette\r
146                 call    LoadPaletteFile\r
147                 jc      TerminateError\r
148 \r
149                 call    LoadIndex\r
150                 jc      TerminateError\r
151 \r
152                 KEYB_START\r
153 \r
154                 call    Beginning       ; Can display an entry screen here\r
155 \r
156         ; This is linked in from Michael Abrash's zen timer code.\r
157         ; (But I wrote the Click myself)\r
158         call    Click\r
159         call    ZTimerOn\r
160 \r
161                 call    MainLoop\r
162 \r
163         call    ZTimerOff\r
164         call    Click\r
165 \r
166                 call    Ending          ; Can display an exit screen here\r
167 \r
168                 KEYB_END\r
169 \r
170 Terminate:      mov     nError,ERR_OK\r
171 TerminateError:\r
172                 mov     ax,cs   ;DOS functions require that DS point\r
173                 mov     ds,ax   ; to text to be displayed on the screen\r
174                 mov     bh,0\r
175                 mov     bl,nError\r
176                 shl     bx,1\r
177                 DOSPRINT msgtblError[bx]\r
178 \r
179                 mov     ax,pages\r
180                 mov     ds,segCode\r
181                 mov     si,offset strNumPages\r
182                 call    Int2Ascii\r
183                 DOSPRINT <offset msgPages>\r
184 \r
185         call    ZTimerReport\r
186 \r
187                 mov     al,nError\r
188                 mov     ah,4ch        ; DOS Terminate\r
189                 int     21h\r
190                 ; Don't need to RET!  We're outta here\r
191 Initialize      ENDP\r
192 \r
193 ;; Clicks the internal speaker.  I use this to indicate that page timing\r
194 ;; has started.\r
195 Click           PROC\r
196                 in      al,61h\r
197                 mov     ah,al\r
198                 or      al,3\r
199                 out     61h,al\r
200 \r
201                 mov     cx,5000         ; (this is an arbitrary delay!)\r
202 spkr_on:        loop    spkr_on\r
203                 mov     al,ah\r
204                 out     61h,al\r
205                 ret\r
206 Click           ENDP\r
207 \r
208 ;; Copied from an old 8088 "Learn Assembly" book and changed a bit\r
209 Int2Ascii       PROC\r
210                 mov     cx,6\r
211                 mov     byte ptr cs:[si],' '\r
212                 mov     byte ptr cs:[si+1],'0'\r
213                 mov     byte ptr cs:[si+2],'0'\r
214                 mov     byte ptr cs:[si+3],'0'\r
215                 mov     byte ptr cs:[si+4],'0'\r
216                 mov     byte ptr cs:[si+5],'0'\r
217                 add     si,6\r
218                 mov     cx,10\r
219                 or      ax,ax\r
220                 jns     clear_divide\r
221                 neg     ax\r
222                 mov     byte ptr cs:[si-6],'-'\r
223 clear_divide:   mov     dx,0\r
224                 div     cx\r
225                 add     dx,'0'\r
226                 dec     si\r
227                 mov     cs:[si],dl\r
228                 or      ax,ax\r
229                 jnz     clear_divide\r
230                 ret\r
231 Int2Ascii       ENDP\r
232 \r
233 ;; Given a filename at DS:DX, reads the file into memory and returns\r
234 ;; a pointer to it as DX:0000.\r
235 ;; Note that this routine obviously will only work correctly for\r
236 ;; a file < 640k in size, but you can bring in files bigger than 64k.\r
237 ;; This code comes from Future Crew's STMIK sampler "Mental Surgery"\r
238 ;; and I commented it up to make it fit in with my stuff a little better.\r
239 ;; Thank you, FC, for releasing that code!  Several of the routines\r
240 ;; in this program were inspired or helped along by having that source...\r
241 ;; Most recently, added in error codes.\r
242 EVEN\r
243 LoadFile        PROC    NEAR\r
244                 ;set: DX=offset to filename\r
245                 ;return: DX=segment of file\r
246 \r
247         ; Open the datafile at DS:DX.\r
248                 mov     ax,3D00h        ; 3D,00 -> Open file, read only\r
249                                         ; DS:DX already points at filename\r
250                 int     21h             ;  returns AX=file handle\r
251                 mov     cl,ERR_FILENOTFOUND\r
252                 jc      ferror\r
253                 mov     bx,ax           ; Store file handle in BX\r
254                 mov     si,bx           ; and also in a variable\r
255 \r
256         ; Get the length of the file so we know how much to allocate\r
257                 mov     ax,4202h        ; 42,02 -> Seek, signed from end\r
258                 mov     cx,0            ; CX:DX is a long file offset,\r
259                                         ; BX is already set as file handle\r
260                 mov     dx,0            ;  zero in this case = end of file\r
261                 int     21h             ; (returns long offset in DX:AX)\r
262                 mov     cl,ERR_FILE\r
263                 jc      ferror\r
264 \r
265 ;;;             shr     dx,1            ; This is original FC code,\r
266 ;;;             rcr     ax,1            ; which I removed because the\r
267 ;;;             shr     dx,1            ; 386 has a nice instruction\r
268 ;;;             rcr     ax,1            ; to do this all!\r
269 ;;;             shr     dx,1            ; But 286 users will want to\r
270 ;;;             rcr     ax,1            ; return to this code, instead\r
271 ;;;             shr     dx,1            ; of SHRD dx,ax,4\r
272 ;;;             rcr     ax,1            ;\r
273 \r
274         ; Now turn that long DX:AX into a number of paragraphs to allocate\r
275         ; for when we read the file.\r
276                 shrd    ax,dx,4         ; Divides long DX:AX by 4,\r
277                 mov     bx,ax           ;  and stores this in BX\r
278                 inc     bx      ; HHMMMM?  One more needed for small #'s\r
279                 mov     ah,48h          ; 48 -> Allocate memory\r
280                                         ; BX already = # of paragraphs\r
281                 int     21h\r
282                 mov     cl,ERR_MEM\r
283                 jc      ferror\r
284                 mov     di,ax           ; store this in a variable\r
285 \r
286         ; Seek the file back to the beginning in order to read it into\r
287         ; the memory we just allocated.\r
288                 mov     ax,4200h        ; 42,00 -> Seek, absolute offset\r
289                 mov     bx,si           ; BX is the file handle.\r
290                 mov     cx,0            ; CX:DX is a long offset\r
291                 mov     dx,0\r
292                 int     21h\r
293                 jc      ferror\r
294 \r
295         ; Now read the file into memory\r
296                 mov     ds,di           ; DS points at alloc'd memory\r
297 ReadBlock:      mov     ah,3fh          ; 3F -> Read file\r
298                 mov     cx,32768        ; read 32768 bytes at a time\r
299                 mov     dx,0            ; DS:DX points at beginning of\r
300                 int     21h             ;  this block of memory.\r
301                 mov     cl,ERR_FILE\r
302                 jc      ferror\r
303                 mov     dx,ds           ; Offset DS by (32768/16), which\r
304                 add     dx,800h         ;  is the number of paragraphs in\r
305                 mov     ds,dx           ;  each block of 32768 bytes.\r
306                 cmp     ax,32768        ; Did we actually read 32768 bytes?\r
307                 je      ReadBlock       ; If so, there's more to read...\r
308                                         ; Otherwise, we've read all the\r
309                                         ;  data in the file.\r
310 \r
311         ; So now, close the file handle.\r
312                 mov     ah,3Eh          ; 3E -> Close file\r
313                                         ; BX still is the file handle\r
314                 int     21h\r
315 \r
316         ; Everything went ok.  Return the segment in DX.\r
317                 mov     dx,di\r
318                 mov     nError,ERR_OK\r
319                 ret\r
320 ferror:         mov     nError,cl\r
321                 ret\r
322 LoadFile        ENDP\r
323 \r
324 ;; Eventually, this should load in an index of all data files to\r
325 ;; allow for filenames to be specified outside of the program.  The\r
326 ;; goal is to make the program have no hardcoded filenames...\r
327 ;; Of course, the structure of this index and its entries will be\r
328 ;; hardcoded, as will the structures of all of the files it includes.\r
329 LoadIndex       PROC    near\r
330                 ret\r
331 LoadIndex       ENDP\r
332 \r
333 ;; Save the current video mode and cursor position with standard\r
334 ;; BIOS calls\r
335 SaveVideo       PROC    near\r
336                 mov     ah,0Fh\r
337                 int     10h             ; Get current display Mode\r
338                 mov     nDisplay,al\r
339                 mov     ah,03h\r
340                 mov     bh,0\r
341                 int     10h\r
342                 mov     wCPos,dx\r
343 \r
344                 mov     ds,segText\r
345                 mov     si,0\r
346                 mov     es,segCode\r
347                 mov     di,offset bufText\r
348                 mov     cx,80*50\r
349             rep movsw\r
350                 ret\r
351 SaveVideo       ENDP\r
352 \r
353 ;; Restore the current video mode and cursor position with standard\r
354 ;; BIOS calls\r
355 RestoreVideo    PROC    near\r
356                 mov     ah,00h\r
357                 mov     al,nDisplay\r
358                 int     10h             ; Get current display Mode\r
359                 mov     ah,02h\r
360                 mov     bh,0\r
361                 mov     dx,wCPos\r
362                 int     10h\r
363 \r
364                 PAL_UPDATE      ; When flipping into text mode, re-do the\r
365                                 ; palette because the BIOS changes it.\r
366 \r
367                 mov     es,segText\r
368                 mov     di,0\r
369                 mov     ds,segCode\r
370                 mov     si,offset bufText\r
371                 mov     cx,80*50\r
372             rep movsw\r
373                 ret\r
374 RestoreVideo    ENDP\r
375 \1a