ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/DOSGame/trunk/BASEFUNC.ASM
Revision: 4
Committed: Wed Feb 11 15:26:06 2026 UTC (8 weeks, 3 days ago) by figdor32
File size: 11850 byte(s)
Log Message:
Initial check-in

File Contents

# User Rev Content
1 figdor32 4 ; ES:DI = String ptr
2     ; RET: DI = End of string ptr
3     BASE_TTYWriteDOSString_ES:
4     .loop:
5     MOV AL, [ES:DI]
6     CMP AL, 0x24
7     JE .end ; The mess of branches is here to avoid printing the $ char
8     CALL BIOS_WriteTTYChar
9     INC DI
10     JMP .loop
11     .end:
12     RET
13    
14    
15     ; ES:DI = String ptr
16     ; RET: DI = End of string ptr
17     BASE_TTYWriteASCIIZString_ES:
18     .loop:
19     MOV AL, [ES:DI]
20     CMP AL, 0x00
21     JE .end ; The mess of branches is here to avoid printing the NUL char
22     CALL BIOS_WriteTTYChar
23     INC DI
24     JMP .loop
25     .end:
26     RET
27    
28     ; DS:DI = String ptr
29     ; RET: DX = End of string ptr
30     BASE_TTYWriteASCIIZString_DS:
31     .loop:
32     MOV AL, [DS:DI]
33     CMP AL, 0x00
34     JE .end ; The mess of branches is here to avoid printing the NUL char
35     CALL BIOS_WriteTTYChar
36     INC DI
37     JMP .loop
38     .end:
39     RET
40     ; DS:DX = ASCIIZ Filename ptr
41     ; OUT: ES = Loaded file, remember to free it with DOS_FreeMemory
42     BASE_AllocLoadFile:
43     ;
44     CALL DOS_OpenReadonly ; We only need DX set, which is set by the caller
45     JC ERROR_GeneralDOSError
46     PUSH AX ; Store the file handle on the stack
47     MOV BX, 4096 ; Allocate a full segment, we'll modify that in a second
48     CALL DOS_AllocateMemory
49     JC ERROR_GeneralDOSError
50     MOV ES, AX ; Segment now in ES
51     POP BX ; File handle now in BX
52     PUSH BX
53     MOV CX, 0xFFFF ; Read to end
54     XOR DX, DX ; Offset in ES:DX
55     CALL DOS_ReadFileIntoES
56     JC ERROR_GeneralDOSError
57     ; AX = Actual number of bytes
58     SHR AX, 4 ; Divide by 16 to get the para number
59     INC AX ; Failsafe if not divisible by 16
60     MOV BX, AX ; Input to INT 21H AH = 4AH requested size in paras
61     ; ES Still has our file segment
62     MOV AH, 4AH ; INT 21H AH = 4AH MODIFY MEMORY BLOCK
63     INT 21H
64     JC ERROR_GeneralDOSError
65     ; BX still has our file handle
66     POP BX ; No it didn't. Debugging moment
67     CALL DOS_CloseFile ; Free it and done
68     JC ERROR_GeneralDOSError
69     RET
70    
71    
72     ; ES:SI = Bitmap ptr, header and everything
73     ; CX = X
74     ; DX = Y
75     BASE_DrawBitmapFromFile:
76     CMP BYTE [ES:SI], 'B' ; Check
77     JNE .badmagic ; The
78     INC SI ; Magic
79     CMP BYTE [ES:SI], 'M' ; Number
80     JNE .badmagic ; Or
81     INC SI ; Fail
82     CMP BYTE [ES:SI], 'A' ; If
83     JNE .badmagic ; Invalid
84    
85     INC SI
86     CMP BYTE [ES:SI], 0x00 ; Bitmap version, 0 is the only valid one
87     JNE .nosupport ; If other, throw an error
88    
89     INC SI
90     CMP BYTE [ES:SI], 0x00 ; Bitmap kind, this fx only supports unindexed bitmaps
91     JNE .nosupport ; If other, throw an error
92     INC SI ; Next field
93     CMP BYTE [ES:SI], 0x01 ; Color range, 0 is 4bpp, 1 is 8bpp, 0 is not supported at this time
94     JNE .nosupport ; Say so
95     INC SI ; Next field
96     MOV WORD AX, [ES:SI] ; Stride, save it in AX
97     ADD SI, 2 ; Bump up by a WORD
98     MOV WORD BX, [ES:SI] ; Lines, save in BX
99     ADD SI, 2 ; And bump up, SI is now our bitmap data
100    
101     PUSH CX
102     ;PUSH DX
103     PUSH DS ; Since the bitmap routine wants the data ptr in DS, we save it
104     MOV CX, ES ; Then mess with intermediates
105     MOV DS, CX ; And set the DS
106     POP ES ; Set ES to our old DS
107     ;POP DX ; Get the Y coord
108     POP CX ; And the X coord
109     PUSH ES ; Save ES (Holding DS) again
110     CALL BASE_DrawBitmap ; And finally draw our bitmap
111     POP DS ; And set DS to its former value
112     RET
113    
114     .badmagic:
115     CALL BIOS_SetVideoMode03H
116     MOV DX, STR_ErrInvalidMagic
117     CALL DOS_PrintString
118     JMP Exit
119     .nosupport:
120     CALL BIOS_SetVideoMode03H
121     MOV DX, STR_ErrNotSupported
122     CALL DOS_PrintString
123     JMP Exit
124     RET
125    
126    
127     ; AL = Color
128     BASE_ClearScreen:
129     SHL EAX, 16 ; Store AX in the upper 16b of EAX
130     MOV AX, [RAM_Framebuffer] ; Segment A000h (VGA framebuffer)
131     MOV ES, AX ; Store in ES
132     XOR DI, DI ; Clear DI, we want to start at the, well, start
133     SHR EAX, 16 ; Restore AX from the upper 16b of EAX
134     ; We need to fill the entirety of EAX with 4 bytes as in [AL:AL:AL:AL]
135     ; There's probably an instruction for that which I'm not aware of...
136     MOV AH, AL ; Now, copy lower 8b of AX to upper 8b of AX
137     MOV CX, AX ; Then cache AX, we set CX later so it's not important here
138     SHL EAX, 16 ; Shift the bits
139     MOV AX, CX ; And fill the lower 16b of EAX with its upper 16b
140     MOV CX, 16000 ; Fill 320 * 200 / 4 DWORDs
141     REP STOSD ; Write EAX to ES:DI, inc DI
142     AND EAX, 0xFFFF ; Remove the upper 16 bits of EAX so that they're not just randomly there
143     RET
144    
145     ; DS:SI = Input
146     ; AX = Stride (MUST be 4 or greater)
147     ; BX = Lines
148     ; CX = X
149     ; DX = Y
150     ; NOTE: EBP is used as general-purpose storage, BP is preserved, but the upper 16 bits are not.
151     ; NOTE: All upper 16 bits of 32-bit registers will be lost
152     BASE_DrawBitmap:
153     ; Let's think about it
154     ; DS:SI = Input
155     ; AX = Stride
156     ; BX = Lines
157     ; CX = X
158     ; DX = Y
159     ; And so
160     ; Wait, we need to save AX, we can't use the SHL/SHR trick because CalculateBitmapOffset uses MUL and ADD...
161     ; But DrawLine destroys DI, and it's unused in CalculateBitmapOffset!
162     MOV DI, AX ; So save AX first
163     SHL EDI, 16 ; Shift it to upper 16b
164     MOV DI, BX ; And save BX in the lower 16b
165     CALL BASE_CalculateBitmapOffset ; X = CX Y = DX; RET AX, But it messes with BX
166     MOV BX, DI ; Then first BX -> DI -> BX
167     SHR EDI, 16 ; Shift
168     MOV CX, DI ; And AX -> DI -> CX
169     ; Now AX = Offset, CX = Stride, DrawLine expects that exactly
170    
171     ; Wait, but we need CX for the counter. Fuck. Could ditch LOOP and use CMP/Jxx...
172     ;XOR DX, DX ; Okay, so we can safely clean this, we already calc'd the offset
173     ;INC BX ; Implementation detail because JLE is weird
174     MOV DX, BX
175     MOV BX, CX ; Backup the stride
176     SHL EBP, 16 ; Okay, we're doing A LOT of weirdness here, we're using the stack pointer as general-putpose storage
177     MOV BP, DX ; Store the lines there
178     .loop:
179     CALL BASE_DrawImageLine ; Expects AX = Offset, CX = Stride, DS:SI = Input, Destroys DI
180     ADD SI, CX ; Increment the data ptr by stride
181     ADD AX, 320 ; And increment the offset by 320 to wrap around
182     ;INC DX ; Finally, DX is our line counter, so increment it by 1
183     ;CMP DX, BX ; And compare it against lines + 1
184     ;JNE .loop ; If not there yet, loop
185     DEC DX
186     JNZ .loop
187     MOV AX, BX ; And bring back the stride
188     MOV BX, BP ; Now get back the lines from the base pointer
189     SHR EBP, 16 ; And fix the base pointer or the program will... well...
190     RET
191    
192     ; CX = X
193     ; DX = Y
194     ; RET: AX = Offset
195     BASE_CalculateBitmapOffset:
196     PUSH DX
197     MOV AX, DX ; AX = Y
198     MOV BX, 320
199     MUL BX ; DX:AX = Y * 320
200     POP DX
201     ADD AX, CX ; AX = offset
202     RET
203    
204     ; AX = Offset
205     ; CX = Count/Stride (MUST be 4 or greater, and a power of 2)
206     ; NOTE: Make sure the upper 16 bits of the 32-bit regs are clear and not important
207     ; But, 16-bit registers are preserved
208     ; Destroys DI
209     ; DS:SI = Input
210     BASE_DrawImageLine:
211     ; Okay, so
212     ; First of all, MOVSx copies from DS:SI to ES:DI
213     ; So we need DI to be the offset with regards to the framebuffer
214     ; And that offset can be calculated via BASE_CalculateBitmapOffset
215     MOV DI, AX
216     SHL EBX, 16 ; Save BX in the upper 16b of EBX
217     MOV BX, SI ; Then store the old SI in lower 16b of EBX
218     ; ES is used quite a bit throughout the program, so we save it
219     SHL EDX, 16 ; Save DX in the upper 16b of EDX
220     MOV DX, ES ; Then save ES in DX
221    
222     SHL EAX, 16 ; Store AX in the upper 16 bits of EAX
223     ; Then we set ES to the framebuffer segment address
224     MOV AX, [CS:RAM_Framebuffer] ; Working framebuffer
225     MOV ES, AX ; DO NOT Assume CS = DS
226    
227     ;
228     MOV AX, CX ; Store CX in the temporarily free AX
229    
230     ; === Note note note ===
231     ; Don't touch EAX/AX/AL/AH before after the MOV CX, AX instruction
232     ; Pretty much every procedure call messes with it, so just don't
233     ; === Note note note ===
234    
235     ; Since we're using MOVSD, we need to do / 4
236     SHR CX, 2
237    
238     ; And go ahead
239     REP MOVSD ; DS:SI -> ES:DI
240    
241     MOV CX, AX ; Bring back CX and then
242     SHR EAX, 16 ; Bring back the old AX
243    
244     MOV SI, BX ; Restore SI
245     SHR EBX, 16 ; And restore BX
246    
247     MOV ES, DX ; Restore ES
248     SHR EDX, 16 ; And restore DX
249     RET
250    
251     ; AL = Color
252     ; CX = X
253     ; DX = Y
254     BASE_DrawPixel:
255    
256     PUSH AX
257     MOV AX, [RAM_Framebuffer] ; Segment A000h (VGA framebuffer)
258     MOV ES, AX
259    
260    
261     ; Coordinates
262     ; MOV CX, 100 ; X
263     ; MOV DX, 50 ; Y
264    
265     ; Calculate offset: offset = Y * 320 + X
266    
267     ;MOV AX, DX ; AX = Y
268     ;MOV BX, 320
269     ;MUL BX ; DX:AX = Y * 320
270     ;ADD AX, CX ; AX = offset
271    
272     CALL BASE_CalculateBitmapOffset
273    
274     MOV DI, AX
275     POP AX
276     ; MOV AL, 0x4F ; Color index (some pinkish violet maybe?)
277     STOSB ; Write AL to ES:DI, inc DI
278     RET
279    
280     ; Wait for the vertical blanking period, do nothing and return.
281     ; Use BASE_Present instead for rendering
282     BASE_WaitForVerticalBlank:
283     ;PUSHA
284     PUSH AX
285     PUSH DX
286     MOV DX, 0x3DA
287     .v1: IN AL, DX
288     TEST AL, 0x08
289     JZ .v1 ; Wait for VBLANK to begin
290     .v2: IN AL, DX
291     TEST AL, 0x08
292     JNZ .v2 ; Wait for VBLANK to end
293     ;POPA
294     POP DX
295     POP AX
296     RET
297    
298     ; Wait for the vertical retrace, fill the VGA framebuffer, wait for the vertical retrace to end, and return
299     ; No input
300     BASE_Present:
301     PUSH AX ; Save AX
302     PUSH DX ; Then save DX
303     MOV DX, 0x3DA
304     .v1: IN AL, DX
305     TEST AL, 0x08
306     JZ .v1 ; Wait for VBLANK to begin
307    
308     PUSH DS ; Importantly, store the old data segment because the code will crap itself if we don't bring it back
309     MOV DS, [RAM_Framebuffer] ; Working buffer
310    
311     MOV AX, 0xA000
312     MOV ES, AX ; VGA Framebuffer
313    
314     MOV CX, 16000 ; 320 * 200 / 4
315     XOR SI, SI ; Clear source offset
316     XOR DI, DI ; And clear destination offset
317     REP MOVSD ; TIMES CX DS:SI -> ES:DI
318     POP DS ; Restore the data segment
319    
320     MOV DX, 0x3DA
321     .v2: IN AL, DX
322     TEST AL, 0x08
323     JNZ .v2 ; Wait for VBLANK to end
324     POP DX ; Restore old DX
325     POP AX ; And restore old AX
326     RET
327    
328     ; ES = Game file segment
329     ; Exit on fail
330     BASE_VerifyGameFileMagic:
331     ; Magic is DGF and then 0xCF
332     MOV AL, 'D'
333     MOV AH, [ES:0]
334     CMP AL, AH
335     JNE .badmagic
336     MOV AL, 'G'
337     MOV AH, [ES:1]
338     CMP AL, AH
339     JNE .badmagic
340     MOV AL, 'F'
341     MOV AH, [ES:2]
342     CMP AL, AH
343     JNE .badmagic
344     MOV AL, 0xCF
345     MOV AH, [ES:3]
346     CMP AL, AH
347     JNE .badmagic
348     JMP .goodmagic
349     .badmagic:
350     MOV DX, STR_ErrInvalidMagic
351     CALL DOS_PrintString
352     JMP Exit
353     .goodmagic:
354     RET
355    
356     ; AL = 0 = 16K 1 = 32K 2 = 64L
357     ; RET: AX = Segment or Early exit
358     BASE_AllocFileMem:
359     ; Not using a lookup table because it'd be overkill
360     CMP AL, 0
361     JE .a16k
362     CMP AL, 1
363     JE .a32k
364     CMP AL, 2
365     JE .a64k
366     MOV DX, STR_ErrInvalidAllocation
367     CALL DOS_PrintString
368     JMP Exit
369     .a16k:
370     MOV BX, 1024
371     JMP .alnst
372     .a32k:
373     MOV BX, 2048
374     JMP .alnst
375     .a64k:
376     MOV BX, 4096
377     .alnst:
378     CALL DOS_AllocateMemory
379     JC ERROR_GeneralDOSError
380     RET