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, 4 days ago) by figdor32
File size: 11850 byte(s)
Log Message:
Initial check-in

File Contents

# Content
1 ; 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