This repository has been archived by the owner on Dec 24, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 92
/
L23-1.ASM
555 lines (551 loc) · 14.3 KB
/
L23-1.ASM
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
; Sample VGA program.
; Animates four balls bouncing around a playfield by using
; page flipping. Playfield is panned smoothly both horizontally
; and vertically.
; By Michael Abrash.
;
stack segment para stack 'STACK'
db 512 dup(?)
stack ends
;
MEDRES_VIDEO_MODE equ 0 ;define for 640x350 video mode
; comment out for 640x200 mode
VIDEO_SEGMENT equ 0a000h ;display memory segment for
; true VGA graphics modes
LOGICAL_SCREEN_WIDTH equ 672/8 ;width in bytes and height in scan
LOGICAL_SCREEN_HEIGHT equ 384 ; lines of the virtual screen
; we'll work with
PAGE0 equ 0 ;flag for page 0 when page flipping
PAGE1 equ 1 ;flag for page 1 when page flipping
PAGE0_OFFSET equ 0 ;start offset of page 0 in VGA memory
PAGE1_OFFSET equ LOGICAL_SCREEN_WIDTH * LOGICAL_SCREEN_HEIGHT
;start offset of page 1 (both pages
; are 672x384 virtual screens)
BALL_WIDTH equ 24/8 ;width of ball in display memory bytes
BALL_HEIGHT equ 24 ;height of ball in scan lines
BLANK_OFFSET equ PAGE1_OFFSET * 2;start of blank image
; in VGA memory
BALL_OFFSET equ BLANK_OFFSET + (BALL_WIDTH * BALL_HEIGHT)
;start offset of ball image in VGA memory
NUM_BALLS equ 4 ;number of balls to animate
;
; VGA register equates.
;
SC_INDEX equ 3c4h ;SC index register
MAP_MASK equ 2 ;SC map mask register
GC_INDEX equ 3ceh ;GC index register
GC_MODE equ 5 ;GC mode register
CRTC_INDEX equ 03d4h ;CRTC index register
START_ADDRESS_HIGH equ 0ch ;CRTC start address high byte
START_ADDRESS_LOW equ 0dh ;CRTC start address low byte
CRTC_OFFSET equ 13h ;CRTC offset register
INPUT_STATUS_1 equ 03dah ;VGA status register
VSYNC_MASK equ 08h ;vertical sync bit in status register 1
DE_MASK equ 01h ;display enable bit in status register 1
AC_INDEX equ 03c0h ;AC index register
HPELPAN equ 20h OR 13h ;AC horizontal pel panning register
; (bit 7 is high to keep palette RAM
; addressing on)
dseg segment para common 'DATA'
CurrentPage db PAGE1 ;page to draw to
CurrentPageOffset dw PAGE1_OFFSET
;
; Four plane's worth of multicolored ball image.
;
BallPlane0Image label byte ;blue plane image
db 000h, 03ch, 000h, 001h, 0ffh, 080h
db 007h, 0ffh, 0e0h, 00fh, 0ffh, 0f0h
db 4 * 3 dup(000h)
db 07fh, 0ffh, 0feh, 0ffh, 0ffh, 0ffh
db 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh
db 4 * 3 dup(000h)
db 07fh, 0ffh, 0feh, 03fh, 0ffh, 0fch
db 03fh, 0ffh, 0fch, 01fh, 0ffh, 0f8h
db 4 * 3 dup(000h)
BallPlane1Image label byte ;green plane image
db 4 * 3 dup(000h)
db 01fh, 0ffh, 0f8h, 03fh, 0ffh, 0fch
db 03fh, 0ffh, 0fch, 07fh, 0ffh, 0feh
db 07fh, 0ffh, 0feh, 0ffh, 0ffh, 0ffh
db 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh
db 8 * 3 dup(000h)
db 00fh, 0ffh, 0f0h, 007h, 0ffh, 0e0h
db 001h, 0ffh, 080h, 000h, 03ch, 000h
BallPlane2Image label byte ;red plane image
db 12 * 3 dup(000h)
db 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh
db 0ffh, 0ffh, 0ffh, 07fh, 0ffh, 0feh
db 07fh, 0ffh, 0feh, 03fh, 0ffh, 0fch
db 03fh, 0ffh, 0fch, 01fh, 0ffh, 0f8h
db 00fh, 0ffh, 0f0h, 007h, 0ffh, 0e0h
db 001h, 0ffh, 080h, 000h, 03ch, 000h
BallPlane3Image label byte ;intensity on for all planes,
; to produce high-intensity colors
db 000h, 03ch, 000h, 001h, 0ffh, 080h
db 007h, 0ffh, 0e0h, 00fh, 0ffh, 0f0h
db 01fh, 0ffh, 0f8h, 03fh, 0ffh, 0fch
db 03fh, 0ffh, 0fch, 07fh, 0ffh, 0feh
db 07fh, 0ffh, 0feh, 0ffh, 0ffh, 0ffh
db 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh
db 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh
db 0ffh, 0ffh, 0ffh, 07fh, 0ffh, 0feh
db 07fh, 0ffh, 0feh, 03fh, 0ffh, 0fch
db 03fh, 0ffh, 0fch, 01fh, 0ffh, 0f8h
db 00fh, 0ffh, 0f0h, 007h, 0ffh, 0e0h
db 001h, 0ffh, 080h, 000h, 03ch, 000h
;
BallX dw 15, 50, 40, 70 ;array of ball x coords
BallY dw 40, 200, 110, 300 ;array of ball y coords
LastBallX dw 15, 50, 40, 70 ;previous ball x coords
LastBallY dw 40, 100, 160, 30 ;previous ball y coords
BallXInc dw 1, 1, 1, 1 ;x move factors for ball
BallYInc dw 8, 8, 8, 8 ;y move factors for ball
BallRep dw 1, 1, 1, 1 ;# times to keep moving
; ball according to current
; increments
BallControl dw Ball0Control, Ball1Control ;pointers to current
dw Ball2Control, Ball3Control ; locations in ball
; control strings
BallControlString dw Ball0Control, Ball1Control ;pointers to
dw Ball2Control, Ball3Control ; start of ball
; control strings
;
; Ball control strings.
;
Ball0Control label word
dw 10, 1, 4, 10, -1, 4, 10, -1, -4, 10, 1, -4, 0
Ball1Control label word
dw 12, -1, 1, 28, -1, -1, 12, 1, -1, 28, 1, 1, 0
Ball2Control label word
dw 20, 0, -1, 40, 0, 1, 20, 0, -1, 0
Ball3Control label word
dw 8, 1, 0, 52, -1, 0, 44, 1, 0, 0
;
; Panning control string.
;
ifdef MEDRES_VIDEO_MODE
PanningControlString dw 32, 1, 0, 34, 0, 1, 32, -1, 0, 34, 0, -1, 0
else
PanningControlString dw 32, 1, 0, 184, 0, 1, 32, -1, 0, 184, 0, -1, 0
endif
PanningControl dw PanningControlString ;pointer to current location
; in panning control string
PanningRep dw 1 ;# times to pan according to current
; panning increments
PanningXInc dw 1 ;x panning factor
PanningYInc dw 0 ;y panning factor
HPan db 0 ;horizontal pel panning setting
PanningStartOffset dw 0 ;start offset adjustment to produce vertical
; panning & coarse horizontal panning
dseg ends
;
; Macro to set indexed register P2 of chip with index register
; at P1 to AL.
;
SETREG macro P1, P2
mov dx,P1
mov ah,al
mov al,P2
out dx,ax
endm
;
cseg segment para public 'CODE'
assume cs:cseg, ds:dseg
start proc near
mov ax,dseg
mov ds,ax
;
; Select graphics mode.
;
ifdef MEDRES_VIDEO_MODE
mov ax,010h
else
mov ax,0eh
endif
int 10h
;
; ES always points to VGA memory.
;
mov ax,VIDEO_SEGMENT
mov es,ax
;
; Draw border around playfield in both pages.
;
mov di,PAGE0_OFFSET
call DrawBorder ;page 0 border
mov di,PAGE1_OFFSET
call DrawBorder ;page 1 border
;
; Draw all four plane's worth of the ball to undisplayed VGA memory.
;
mov al,01h ;enable plane 0
SETREG SC_INDEX, MAP_MASK
mov si,offset BallPlane0Image
mov di,BALL_OFFSET
mov cx,BALL_WIDTH * BALL_HEIGHT
rep movsb
mov al,02h ;enable plane 1
SETREG SC_INDEX, MAP_MASK
mov si,offset BallPlane1Image
mov di,BALL_OFFSET
mov cx,BALL_WIDTH * BALL_HEIGHT
rep movsb
mov al,04h ;enable plane 2
SETREG SC_INDEX, MAP_MASK
mov si,offset BallPlane2Image
mov di,BALL_OFFSET
mov cx,BALL_WIDTH * BALL_HEIGHT
rep movsb
mov al,08h ;enable plane 3
SETREG SC_INDEX, MAP_MASK
mov si,offset BallPlane3Image
mov di,BALL_OFFSET
mov cx,BALL_WIDTH * BALL_HEIGHT
rep movsb
;
; Draw a blank image the size of the ball to undisplayed VGA memory.
;
mov al,0fh ;enable all memory planes, since the
SETREG SC_INDEX, MAP_MASK ; blank has to erase all planes
mov di,BLANK_OFFSET
mov cx,BALL_WIDTH * BALL_HEIGHT
sub al,al
rep stosb
;
; Set VGA to write mode 1, for block copying ball and blank images.
;
mov dx,GC_INDEX
mov al,GC_MODE
out dx,al ;point GC Index to GC Mode register
inc dx ;point to GC Data register
jmp $+2 ;delay to let bus settle
in al,dx ;get current state of GC Mode
and al,not 3 ;clear the write mode bits
or al,1 ;set the write mode field to 1
jmp $+2 ;delay to let bus settle
out dx,al
;
; Set VGA offset register in words to define logical screen width.
;
mov al,LOGICAL_SCREEN_WIDTH / 2
SETREG CRTC_INDEX, CRTC_OFFSET
;
; Move the balls by erasing each ball, moving it, and
; redrawing it, then switching pages when they're all moved.
;
BallAnimationLoop:
mov bx,( NUM_BALLS * 2 ) - 2
EachBallLoop:
;
; Erase old image of ball in this page (at location from one more earlier).
;
mov si,BLANK_OFFSET ;point to blank image
mov cx,[LastBallX+bx]
mov dx,[LastBallY+bx]
call DrawBall
;
; Set new last ball location.
;
mov ax,[BallX+bx]
mov [LastballX+bx],ax
mov ax,[BallY+bx]
mov [LastballY+bx],ax
;
; Change the ball movement values if it's time to do so.
;
dec [BallRep+bx] ;has current repeat factor run out?
jnz MoveBall
mov si,[BallControl+bx] ;it's time to change movement values
lodsw ;get new repeat factor from
; control string
and ax,ax ;at end of control string?
jnz SetNewMove
mov si,[BallControlString+bx] ;reset control string
lodsw ;get new repeat factor
SetNewMove:
mov [BallRep+bx],ax ;set new movement repeat factor
lodsw ;set new x movement increment
mov [BallXInc+bx],ax
lodsw ;set new y movement increment
mov [BallYInc+bx],ax
mov [BallControl+bx],si ;save new control string pointer
;
; Move the ball.
;
MoveBall:
mov ax,[BallXInc+bx]
add [BallX+bx],ax ;move in x direction
mov ax,[BallYInc+bx]
add [BallY+bx],ax ;move in y direction
;
; Draw ball at new location.
;
mov si,BALL_OFFSET ;point to ball's image
mov cx,[BallX+bx]
mov dx,[BallY+bx]
call DrawBall
;
dec bx
dec bx
jns EachBallLoop
;
; Set up the next panning state (but don't program it into the
; VGA yet).
;
call AdjustPanning
;
; Wait for display enable (pixel data being displayed) so we know
; we're nowhere near vertical sync, where the start address gets
; latched and used.
;
call WaitDisplayEnable
;
; Flip to the new page by changing the start address.
;
mov ax,[CurrentPageOffset]
add ax,[PanningStartOffset]
push ax
SETREG CRTC_INDEX, START_ADDRESS_LOW
mov al,byte ptr [CurrentPageOffset+1]
pop ax
mov al,ah
SETREG CRTC_INDEX, START_ADDRESS_HIGH
;
; Wait for vertical sync so the new start address has a chance
; to take effect.
;
call WaitVSync
;
; Set horizontal panning now, just as new start address takes effect.
;
mov al,[HPan]
mov dx,INPUT_STATUS_1
in al,dx ;reset AC addressing to index reg
mov dx,AC_INDEX
mov al,HPELPAN
out dx,al ;set AC index to pel pan reg
mov al,[HPan]
out dx,al ;set new pel panning
;
; Flip the page to draw to the undisplayed page.
;
xor [CurrentPage],1
jnz IsPage1
mov [CurrentPageOffset],PAGE0_OFFSET
jmp short EndFlipPage
IsPage1:
mov [CurrentPageOffset],PAGE1_OFFSET
EndFlipPage:
;
; Exit if a key's been hit.
;
mov ah,1
int 16h
jnz Done
jmp BallAnimationLoop
;
; Finished, clear key, reset screen mode and exit.
;
Done:
mov ah,0 ;clear key
int 16h
;
mov ax,3 ;reset to text mode
int 10h
;
mov ah,4ch ;exit to DOS
int 21h
;
start endp
;
; Routine to draw a ball-sized image to all planes, copying from
; offset SI in VGA memory to offset CX,DX (x,y) in VGA memory in
; the current page.
;
DrawBall proc near
mov ax,LOGICAL_SCREEN_WIDTH
mul dx ;offset of start of top image scan line
add ax,cx ;offset of upper left of image
add ax,[CurrentPageOffset] ;offset of start of page
mov di,ax
mov bp,BALL_HEIGHT
push ds
push es
pop ds ;move from VGA memory to VGA memory
DrawBallLoop:
push di
mov cx,BALL_WIDTH
rep movsb ;draw a scan line of image
pop di
add di,LOGICAL_SCREEN_WIDTH ;point to next destination scan line
dec bp
jnz DrawBallLoop
pop ds
ret
DrawBall endp
;
; Wait for the leading edge of vertical sync pulse.
;
WaitVSync proc near
mov dx,INPUT_STATUS_1
WaitNotVSyncLoop:
in al,dx
and al,VSYNC_MASK
jnz WaitNotVSyncLoop
WaitVSyncLoop:
in al,dx
and al,VSYNC_MASK
jz WaitVSyncLoop
ret
WaitVSync endp
;
; Wait for display enable to happen (pixels to be scanned to
; the screen, indicating we're in the middle of displaying a frame).
;
WaitDisplayEnable proc near
mov dx,INPUT_STATUS_1
WaitDELoop:
in al,dx
and al,DE_MASK
jnz WaitDELoop
ret
WaitDisplayEnable endp
;
; Perform horizontal/vertical panning.
;
AdjustPanning proc near
dec [PanningRep] ;time to get new panning values?
jnz DoPan
mov si,[PanningControl] ;point to current location in
; panning control string
lodsw ;get panning repeat factor
and ax,ax ;at end of panning control string?
jnz SetnewPanValues
mov si,offset PanningControlString ;reset to start of string
lodsw ;get panning repeat factor
SetNewPanValues:
mov [PanningRep],ax ;set new panning repeat value
lodsw
mov [PanningXInc],ax ;horizontal panning value
lodsw
mov [PanningYInc],ax ;vertical panning value
mov [PanningControl],si ;save current location in panning
; control string
;
; Pan according to panning values.
;
DoPan:
mov ax,[PanningXInc] ;horizontal panning
and ax,ax
js PanLeft ;negative means pan left
jz CheckVerticalPan
mov al,[HPan]
inc al ;pan right; if pel pan reaches
cmp al,8 ; 8, it's time to move to the
jb SetHPan ; next byte with a pel pan of 0
sub al,al ; and a start offset that's one
inc [PanningStartOffset] ; higher
jmp short SetHPan
PanLeft:
mov al,[HPan]
dec al ;pan left; if pel pan reaches -1,
jns SetHPan ; it's time to move to the next
mov al,7 ; byte with a pel pan of 7 and a
dec [PanningStartOffset] ; start offset that's one lower
SetHPan:
mov [HPan],al ;save new pel pan value
CheckVerticalPan:
mov ax,[PanningYInc] ;vertical panning
and ax,ax
js PanUp ;negative means pan up
jz EndPan
add [PanningStartOffset],LOGICAL_SCREEN_WIDTH
;pan down by advancing the start
; address by a scan line
jmp short EndPan
PanUp:
sub [PanningStartOffset],LOGICAL_SCREEN_WIDTH
;pan up by retarding the start
; address by a scan line
EndPan:
ret
;
; Draw textured border around playfield that starts at DI.
;
DrawBorder proc near
;
; Draw the left border.
;
push di
mov cx,LOGICAL_SCREEN_HEIGHT / 16
DrawLeftBorderLoop:
mov al,0ch ;select red color for block
call DrawBorderBlock
add di,LOGICAL_SCREEN_WIDTH * 8
mov al,0eh ;select yellow color for block
call DrawBorderBlock
add di,LOGICAL_SCREEN_WIDTH * 8
loop DrawLeftBorderLoop
pop di
;
; Draw the right border.
;
push di
add di,LOGICAL_SCREEN_WIDTH - 1
mov cx,LOGICAL_SCREEN_HEIGHT / 16
DrawRightBorderLoop:
mov al,0eh ;select yellow color for block
call DrawBorderBlock
add di,LOGICAL_SCREEN_WIDTH * 8
mov al,0ch ;select red color for block
call DrawBorderBlock
add di,LOGICAL_SCREEN_WIDTH * 8
loop DrawRightBorderLoop
pop di
;
; Draw the top border.
;
push di
mov cx,(LOGICAL_SCREEN_WIDTH - 2) / 2
DrawTopBorderLoop:
inc di
mov al,0eh ;select yellow color for block
call DrawBorderBlock
inc di
mov al,0ch ;select red color for block
call DrawBorderBlock
loop DrawTopBorderLoop
pop di
;
; Draw the bottom border.
;
add di,(LOGICAL_SCREEN_HEIGHT - 8) * LOGICAL_SCREEN_WIDTH
mov cx,(LOGICAL_SCREEN_WIDTH - 2) / 2
DrawBottomBorderLoop:
inc di
mov al,0ch ;select red color for block
call DrawBorderBlock
inc di
mov al,0eh ;select yellow color for block
call DrawBorderBlock
loop DrawBottomBorderLoop
ret
DrawBorder endp
;
; Draws an 8x8 border block in color in AL at location DI.
; DI preserved.
;
DrawBorderBlock proc near
push di
SETREG SC_INDEX, MAP_MASK
mov al,0ffh
rept 8
stosb
add di,LOGICAL_SCREEN_WIDTH - 1
endm
pop di
ret
DrawBorderBlock endp
AdjustPanning endp
cseg ends
end start